Skip to content
WebsiteGet started

Reference

Errors

The API error format, the error code catalog and the Hacienda rejections Aster catches before sending.

Every API error uses the same format and a stable error.code. Code against error.code, not against the text in error.message, which may change.

{
"success": false,
"error": {
"code": "validation_error",
"message": "Validation failed",
"errors": {
"items": ["At least one item is required"]
}
},
"timestamp": "2026-03-06T12:00:00Z",
"api_version": "1.0"
}
Field Description
success Always false on an error
error.code Stable code, in English and snake_case
error.message Human-readable description
error.errors Only on validation_error: an object with each field’s path and its list of problems
timestamp Response time, UTC
api_version API version

Authentication, permission, rate-limit and idempotency errors also repeat the message in a top-level message field, for compatibility with older clients.

error.message and the messages in error.errors come in Spanish or English depending on the request’s Accept-Language header. With Accept-Language: en you get:

{
"success": false,
"error": {
"code": "validation_error",
"message": "CABYS code 4292199990299 is not in the Catálogo de Bienes y Servicios (Hacienda error -400).",
"errors": {
"items.0.cabys_code": [
"CABYS code 4292199990299 is not in the Catálogo de Bienes y Servicios (Hacienda error -400)."
]
}
},
"timestamp": "2026-10-08T16:20:11Z",
"api_version": "1.0"
}

The paths in error.errors follow the structure of the JSON you sent: items.0.cabys_code is the cabys_code of the first line (counting from 0) and receiver.id is the receiver’s ID.

hacienda_message, on the other hand, carries Hacienda’s text exactly as Hacienda returned it, untranslated and unabridged.

HTTP error.code When What to do
400 invalid_request The body is missing or not valid JSON Check the body and Content-Type
400 invalid_idempotency_key X-Idempotency-Key is longer than 255 characters Use a shorter key
401 unauthenticated The key is missing, malformed or unknown Check the Authorization header
401 token_expired The key is past its expiry date Create a new key
401 key_revoked The key was revoked Use an active key
401 tenant_unresolved The key’s organization could not be loaded Check that the organization exists
402 plan_required An aster_live_ key was used or created without a paid plan Choose a plan in the dashboard
402 quota_exceeded The plan’s monthly limit plus purchased packs was reached. Returned before signing Upgrade your plan or add a pack at any time; see below
402 subscription_inactive The subscription is not in good standing (for example, a declined charge). Test keys keep working Update the payment method in the dashboard
402 subscription_expired Both the trial and the subscription have ended Renew the plan in the dashboard
403 forbidden The key lacks the permission the endpoint requires Create a key with that permission
403 account_key_required The endpoint manages the account and was called with an organization key Use an account key (created without an organization)
403 organization_limit_reached The plan allows no more organizations Upgrade your plan
403 no_tenant, tenant_inactive, tenant_deleted The organization is not available Contact support
404 not_found The resource doesn’t exist or doesn’t belong to your organization Check the clave or identifier
409 duplicate_clave The clave was already used Don’t retry with the same clave; see Consecutivo (in Spanish)
409 duplicate_consecutive The consecutivo was already used in that environment The number is spent; use a new one
409 organization_exists An organization with that ID already exists in the account Use the existing one
409 idempotency_in_progress Another request with the same X-Idempotency-Key is still running Wait and retry with the same key
422 validation_error One or more fields failed validation. Details in error.errors Fix the listed fields
422 idempotency_key_reused An X-Idempotency-Key was reused with a different body or path Use a new key for each distinct request
422 organization_mismatch The document’s issuer is not the key’s organization Use the key of the issuing organization
422 invalid_clave_consecutive clave was sent without consecutive_number, or the other way around Send both or neither
422 invalid_clave_format, invalid_consecutive_format The clave is not 50 characters or the consecutivo is not 20 digits See Clave (in Spanish)
422 clave_date_mismatch The date inside the clave doesn’t match document.date Build the clave with the issue date
422 fec_clave_id_mismatch On an FEC, the clave doesn’t carry the receiver’s ID Use the buyer’s ID in the clave
422 missing_certificate, missing_credentials The certificate or Hacienda credentials for that environment are missing Upload them in the dashboard
422 certificate_expired The signing certificate for that environment has expired Upload a valid certificate
422 cannot_revoke_current_key A key tried to revoke itself Revoke it with another account key
429 rate_limited The per-minute or per-day request limit was exceeded Wait the seconds in Retry-After
500 internal_error Unexpected Aster error Retry with the same X-Idempotency-Key

None of these errors registers the document or spends the consecutivo, except duplicate_clave and duplicate_consecutive, which mean it was already spent. Billing errors (402) are returned before signing, so you can safely release the number in your system.

402 Payment Required
{
"success": false,
"error": {
"code": "quota_exceeded",
"message": "You have reached your plan's document limit for this month.",
"upgrade_url": "https://aster.astranexo.com/app/billing/plan",
"pack_url": "https://aster.astranexo.com/app/billing/packs"
},
"message": "You have reached your plan's document limit for this month.",
"timestamp": "2026-10-08T16:20:11Z",
"api_version": "1.0"
}

Upgrade your plan or add a pack at any time with the links in error.upgrade_url and error.pack_url (always use the ones in the response). The change is charged to your saved payment method and invoicing resumes within a minute. Test mode has no usage limit. See what counts toward usage (in Spanish).

Every authenticated response carries the headers of the limit that applies:

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 298
X-RateLimit-Reset: 1791476460

When you exceed it, the response is 429 rate_limited with Retry-After in seconds. Rejected requests don’t count toward the limit. See Límites (in Spanish).

Hacienda rejections Aster catches before sending

Section titled “Hacienda rejections Aster catches before sending”

A Hacienda rejection spends the consecutivo and forces you to issue a replacement document. That’s why Aster checks the most common rejection causes before signing and answers 422 validation_error with Hacienda’s code in the message, without sending anything.

Hacienda code What Aster checks
-107, -109, -111, -190, -290, -476, -487 Calculations: line amounts, subtotals, tax, exemption, net tax, tax assumed by the issuer, tax breakdown, services vs. goods classification and summary totals. Compared at 5 decimal places with Hacienda’s tolerance
-38 The issuer’s and receiver’s IDs are registered with Hacienda
-400 Each line’s CABYS code exists in the Catálogo de Bienes y Servicios
-483, -485 An exempt CABYS code is invoiced with rate code 10 (Tarifa Exenta), not another 0% rate
-491 Reference code 99 (Otros) carries reference.code_other_description
-505 The rate code (rate_code) matches the percentage (rate)
-509 Every CABYS code on a credit or debit note appears in the original document
-512 A credit note’s total doesn’t exceed the original document’s total
-17 A credit or debit note’s receiver is the same as the original document’s
-29 The referenced document exists and was accepted by Hacienda
-99 The clave was never used before (answers 409 duplicate_clave)

Aster also validates the full version 4.4 structure: required fields per document type, lengths, ID formats (including alphanumeric corporate IDs), units of measure against the CABYS chapter, current reference codes and the IVA devuelto (returned VAT) rules.

The note checks (-509, -512, -17, -29) use the original document stored in Aster. If the original is not in Aster, those content checks are skipped and the verdict is left to Hacienda.

Codes -37 and -410 are warnings: Hacienda accepts the document with minor observations. Aster marks it accepted and keeps the text in hacienda_message. See Ciclo de vida (in Spanish).

If Hacienda rejects a document for a rule Aster cannot check beforehand, the document ends in rejected, you receive the document.rejected event and Hacienda’s detail is in hacienda_message. To fix it, issue a new document that replaces the rejected one (see Consecutivo, in Spanish).