1. Reference

Errors

This page uses these terms:

  • Your organization: the account of your company in the Wafeq ASP portal. Your API keys, OAuth client and subscription belong to your organization.
  • Mode: Live or Sandbox. Each mode has its own credentials and data.
  • Grant: the permission that a business gives to your organization. A grant has an ID (tgr_…) and scopes. The scopes are the permissions that the business approved.
  • Taxpayer: a business from which your organization has an active grant. Its ID is the Taxpayer ID (txpay_…).
  • Document: an invoice or a credit note. Its ID is the document ID (inv_…).
  • Check: a call to a /validate endpoint, for example POST /invoices/validate. Wafeq ASP runs its checks and keeps nothing.
  • Submission: a call to POST /invoices, POST /credit-notes, or to one of the two self-billing endpoints.
  • Buyer: the business that receives the document.
  • Peppol ID: the address of a business on Peppol. For a UAE business, it is 0235: and then its TIN.
  • Correction: a submission with corrects_document_id. It replaces a document that the provider of the buyer rejected.
  • Document credit: a prepaid unit of your organization. In Live, a document can use one credit.

Use this page when Wafeq ASP refuses a call. Each section is about one situation and tells you what to do. For the normal flow of a submission, refer to Submit a document.

How to read a refusal

Wafeq ASP gives a refusal in one of these forms:

FormWhere the code is
HTTP 4xx or 5xx, detail is an objectdetail.code. detail.message explains it, if it is there.
HTTP 4xx or 5xx, detail is a textThere is no code. Use the HTTP status and the text.
HTTP 422, detail is a listThere is no code. Each item names a field that is not correct.
HTTP 200, success: falsestatus. The error field explains it.
HTTP 429There is no code. The error field explains it.
OAuth endpointserror. The error_description field explains it.

Example of a refusal with detail.code:

{
  "detail": {
    "code": "idempotency_key_reused",
    "submission_request_id": "subr_0123456789ABCDEFGHIJ",
    "message": "This key belongs to a different payload or an unfinished submission. Retry the same payload/key for its outcome; do not create a new send."
  }
}

Example of a submission that Wafeq ASP refuses with HTTP 200. The example shows only some of the fields:

{
  "success": false,
  "invoice_id": "INV-2026-0042",
  "status": "duplicate_number",
  "error": "Document number 'INV-2026-0042' was already submitted successfully. Use a unique number (resubmit the same number only to retry a failed submission)."
}

Many refusals of a submission have the same code in a check. A check gives each problem as an item in errors. Thus, check each document before you submit it.

Credentials and access

These refusals are about your credentials and your grants.

CodeHTTPMeaningWhat to do
—401The API key or the access token is missing, not correct, or from the other mode.Send a valid credential of the correct mode.
—400Your call uses an API key, but it has no x-ae-taxpayer-id header.Add the Taxpayer ID in x-ae-taxpayer-id.
—404Wafeq ASP does not know the Taxpayer ID in this mode.Use the Taxpayer ID from the connection. Do not use the TIN.
—403The taxpayer gave your organization no active grant.Connect the business again.
grant_not_active403The grant in x-ae-grant-id is not active, or it is not from this taxpayer.Read GET /grants. Connect the business again if necessary.
insufficient_scope403The grant does not have the scope that the call needs. detail.scope names it.Start the authorization flow again with this scope.
taxpayer_token_required403You sent an organization access token for a taxpayer call.Use a token from the authorization flow, or your API key.
—403The text is Taxpayer is …. The taxpayer is not active, for example because it deregistered.Do not submit documents for it. You can still read its documents.
—403The text is Taxpayer connection is not active.Read GET /grants. Connect the business again if necessary.
  • A 401 for an access token has the header WWW-Authenticate: Bearer error="invalid_token". An access token expires after one hour. Get a new token with your refresh token.
  • An access token acts for one grant. If your x-ae-taxpayer-id or x-ae-grant-id header names a different taxpayer or grant, Wafeq ASP answers 403.
  • GET /invoices/{document_id}/reports answers 422 instead of 400 when x-ae-taxpayer-id is missing.

OAuth token endpoint

POST /oauth/token, POST /oauth/revoke and POST /oauth/taxpayer-registration give errors in the OAuth format.

CodeHTTPMeaningWhat to do
invalid_client401The client ID or the client secret is not correct.Use the OAuth client of the correct mode.
invalid_grant400The code or the refresh token is not valid. Refer to the list below.Start the authorization flow again.
unsupported_grant_type400grant_type is not authorization_code, refresh_token or client_credentials.Correct grant_type.

An invalid_grant error has one of these causes:

  • The authorization code is not correct, it expired, or your app used it already.
  • redirect_uri is different from the value in the authorization request.
  • The PKCE check failed. code_verifier does not match code_challenge.
  • The refresh token is not correct, it expired, or Wafeq ASP revoked it.

If your app sends a used code or an old refresh token again, Wafeq ASP revokes all the tokens of that grant. To get new tokens, start the authorization flow again.

OAuth authorization page

When the authorization request is not correct, Wafeq ASP redirects the business to your callback URL. The URL contains error, error_description and state.

CodeMeaningWhat to do
invalid_requestA parameter is not correct. error_description names it.Correct the parameter.
invalid_scopescope is empty, or it contains an unknown scope.Send only the scopes that Authentication lists.
unsupported_response_typeresponse_type is not code.Send response_type=code.
access_deniedThe business declined your app.Wafeq ASP created no grant. Ask the business before you try again.

invalid_request has these causes:

  • PKCE is missing, or code_challenge_method is not S256.
  • code_challenge does not have 43 to 128 characters.
  • tin_hint is not a 10-digit TIN.
  • state has more than 1024 characters.
  • external_id does not have 1 to 128 visible characters.
  • The legal registration hint is not complete. PAS also needs legal_registration_issuing_country.

If the client ID is unknown, or the redirect URI is not in your list, Wafeq ASP does not redirect. The authorization page shows the error.

Billing

These refusals occur only in Live. Sandbox has no billing.

CodeHTTPMeaningWhat to do
subscription_required402Your organization has no active subscription.Buy or renew the subscription in the Wafeq ASP portal.
wallet_insufficient_funds402Your organization has no free document credit.Buy document credits in the Wafeq ASP portal.
billing_status_unavailable503Wafeq ASP cannot get the current status of your subscription.Wait a short time, then try again.
  • subscription_required applies to checks and to submissions.
  • wallet_insufficient_funds gives requiredDocuments and availableDocuments.
  • wallet_insufficient_funds also applies when your app reads a received document that Wafeq ASP holds. Wafeq ASP holds a received document when your organization cannot pay for it. Then detail.document_id names the document.

When a new business approves your app in Live, Wafeq ASP checks your subscription and your free taxpayer seats. The business sees these refusals on the approval page. Your app does not receive them:

  • subscription_required (402): your organization has no active subscription.
  • taxpayer_seat_limit_reached (409): all the taxpayer seats of your subscription are in use.
  • unverified_client_limit_reached (409): your app is not verified, and it has 25 businesses in Live.

For these conditions, refer to Connect a taxpayer.

Request shape

CodeHTTPMeaningWhat to do
—422The body or a header does not match the API reference. detail is a list.Correct each field that the list names.
invalid_submission_payload422A value in the body is not valid JSON.Remove values such as NaN or Infinity.
invalid_participant_id422The Peppol ID in the path does not have the form scheme:value.Send the Peppol ID, for example 0235:1999200000.

Each item in the detail list has these fields:

  • loc: the path to the field, for example ["body", "customer", "address"].
  • msg: what is not correct.
  • type: the kind of problem, for example missing.

These two headers also cause this error if they are not correct:

  • Idempotency-Key must have 1 to 128 visible ASCII characters.
  • Prefer accepts only the value respond-async.

Idempotency

These refusals come from the Idempotency-Key header of a submission.

CodeHTTPMeaningWhat to do
idempotency_key_required422This submission needs an Idempotency-Key. Refer to the list below.Send the submission again with a key.
idempotency_key_reused409The key belongs to a submission with a different body.Send the original body with this key, or use a new key.
idempotency_in_progress409The first request with this key is still in progress.Wait, then send the same request again.
idempotency_unconfirmed409The first request with this key stopped. Its result is not known.Refer to the list below.
idempotency_unavailable503Wafeq ASP cannot store the submission or its result.Send the same request again, with the same key.
document_already_submitted409The taxpayer already submitted a document with this number.Do not submit it again. Track the first submission.
queued_delivery_unavailable503Queued delivery is not available at this time.Try again later.

A submission needs an Idempotency-Key in these cases:

  • A submission with Prefer: respond-async (queued delivery).
  • A submission that Wafeq ASP reports to the FTA only.
  • A correction.

Wafeq ASP stores the response of each key when the submission ends. A refusal is also a response. For example, Wafeq ASP stores a 402 and each HTTP 200 with success: false. If you send the same key again, you get the stored response again. Thus, after such a refusal, correct the cause and use a new key. Wafeq ASP accepted nothing, so a new key does not submit the document two times.

Some refusals come before Wafeq ASP stores anything: 400, 401 and 404 for credentials, 422 with a list, and 429. After these refusals, you can send the same key again.

After idempotency_unconfirmed, do these steps:

  1. Do not send the request again with the same key. The answer does not change.
  2. Look for the number of the document in GET /invoices or GET /credit-notes. Filter by the issue date of the document.
  3. If the document is in the list, Wafeq ASP accepted it. Track it.
  4. If the document is not in the list, submit it again with a new key.

Document checks

Wafeq ASP checks each document against the UAE rules. A check gives each problem in errors. A submission stops at the first kind of problem, and gives it in status.

Errors from the UAE rules

A check returns errors, warnings and info. Each item has these fields:

  • code: the code of the problem.
  • message: the explanation.
  • severity: error, warning or info.
  • location: where the problem is in the XML document that Wafeq ASP makes from your request, or null.

A submission with this kind of problem returns HTTP 200, success: false and status: validation_failed. validation_errors then contains a maximum of 10 items. These items have code, message and location. To see all the problems, check the document.

Read the codes in this way:

  • SCH: followed by a rule ID is an official UAE rule of PINT-AE, the UAE e-invoice format. For example, SCH:ibr-167-ae.
  • The message of an SCH: rule uses the field numbers of the PINT-AE specification. IBT-… is a field. IBG-… is a group of fields. BTAE-… is a field that only the UAE uses.
  • UBL-004 means that the XML does not match the UBL schema.

Example: SCH:ibr-167-ae says that a line with VAT category E has no VAT exemption reason code (IBT-186). Add tax_exemption_reason_code to the line. For the VAT fields, refer to VAT on each line.

The warnings SCH-002, SCH-003 and UBL-003 tell you that Wafeq ASP could not run all the checks. Check the document again later.

During a queued submission, or a submission that goes to the FTA only, Wafeq ASP must run all the checks. If it cannot, it answers 503 with a text and no code. Try again later.

Other problems with the document

A submission returns these codes in status, with HTTP 200 and success: false. A check returns the same codes in errors, except where the table says something different.

CodeMeaningWhat to do
duplicate_numberThe taxpayer already used this number for a document that succeeded. A check gives duplicate_invoice_number.Use a new number.
missing_supplierThe taxpayer has no registered profile. A self-billed document gives missing_customer.Ask the business to complete its onboarding.
incomplete_profileThe registered profile of the taxpayer has no street or no city.Ask the business to add them to its registered profile.
seller_without_trn_taxable_linesThe seller has no VAT TRN, and a line has a VAT category other than E, O or Z.Use E, O or Z on each line.
buyer_legal_registration_requiredA commercial document (480 or 81) has no legal registration for the buyer.Add customer.legal_registration.
transaction_flags_not_allowedA commercial document (480 or 81) has a special scenario that it cannot have, for example a deemed supply.Remove the flag from transaction_type_code.
previous_invoice_not_foundThe taxpayer did not issue a document with this previous_document_id.Use the document ID of an invoice of this taxpayer.
invalid_previous_documentThe original is not an invoice that the taxpayer issued, its type does not match, or it has no number or date.Use the document ID of the invoice that the credit note corrects.
previous_invoice_party_mismatchThe credit note and the original invoice have different buyers. For self-billing, they have different sellers.Use the party of the original invoice.
previous_invoice_lookup_failedWafeq ASP could not read the original invoice.Try again later.
conversion_failedWafeq ASP could not make the XML document from your request.Read error, and correct the request.
profile_mismatchThe value of profile does not match the document.Do not send profile. Wafeq ASP then uses the correct value.

For the document types and the legal registration, refer to Document types. For special scenarios, refer to Special scenarios.

Buyer lookup on Peppol

Wafeq ASP looks for the buyer on Peppol before it delivers a document. These codes come from this lookup.

CodeWhereMeaningWhat to do
smp_unavailableCheck: warningWafeq ASP could not look for the buyer at this time.Submit as usual. The submission looks again.
smp_unavailableSubmission: 503The lookup failed at this time. Wafeq ASP accepted nothing.Send the same request again later, with the same key.
smp_unavailableSubmission: 200, statusThe lookup failed at this time.Submit again later, with a new key.
smp_lookup_failedCheck: error. Submission: 200, statusThe buyer is not on Peppol, and the document cannot go to the FTA only.Read Who receives the document.
smp_lookup_errorCheck: errorThe lookup stopped with an error.Check the document again later.
reporting_only_unavailableCheck: error. Submission: 503Wafeq ASP cannot report this document to the FTA at this time.Try again later. For a submission, use the same key.
reporting_route_unavailableSubmission: 200, statusThe document must go to the FTA only, but the submission did not select this route.Check the document again, then submit it again with a new key.

A check also gives codes that are not problems:

  • fta_reporting_only (warning): Wafeq ASP will report the document to the FTA only. The buyer gets no delivery.
  • smp_resolved (info): Wafeq ASP found the buyer on Peppol.
  • sandbox_simulated_delivery and sandbox_simulated_reporting (info): Sandbox simulates the delivery or the report.

To look for a buyer before you build a document, send GET /recipients/{participant_id}/reachability. If error is not null, the lookup did not give an answer. Then reachable: false means "not known", not "not on Peppol".

Corrections

These refusals apply to a correction, and to POST /invoices/{document_id}/void. For the procedure, refer to Correct or cancel a document.

CodeHTTPMeaningWhat to do
correction_not_ready409Wafeq ASP is still processing the report of the original document.Wait, then send the same request again, with the same key.
correction_number_or_type_mismatch422The number or the type is different from the original.Use the number and the type of the original.
c3_validation_rejection_required409The provider of the buyer did not reject the original with BV or SV.You cannot correct this document. Refer to the procedure.
correction_not_availableCheck onlyThe original has a replacement already, or a different recovery is in progress.Do not correct it again.
correction_not_ready_or_already_replaced409The original is not ready for a correction, or another document replaced it.Read the original with GET /invoices/{document_id}.
different_recovery_requires_reconciliation409A different recovery of the original is in progress. Wafeq ASP must resolve it first.Contact Wafeq ASP.
transport_reconciliation_required409The delivery of the original is in progress at this moment.Wait, then send the same request again.
queued_document_not_found404The original is not a document of this taxpayer with queued delivery.You can correct only documents that used queued delivery.
document_owner_changed403Your organization did not submit the original.Only the organization that submitted the original can correct it.
sandbox_reporting_disabled403Corrections are not available in Sandbox.—
delivery_unsettled409Void only. The delivery of the original is not complete, or a recovery is in progress.Try again after the delivery ends.
  • correction_not_ready also contains ready: false and reporting_recovery, the current state of the recovery.
  • These codes tell you that Wafeq ASP does not have the records that a correction needs: document_evidence_unavailable, c3_evidence_unavailable and correction_lineage_invalid. Contact Wafeq ASP.
  • A check of a correction gives these codes as items in errors. If Wafeq ASP cannot check the original, the item is correction_validation_unavailable. Check the document again later.

POST /invoices/{document_id}/void also gives these refusals, with a text and no code:

  • 400: the document is a credit note, or the taxpayer received it.
  • 409: a credit note already credits the invoice.
  • 422: Wafeq ASP cannot rebuild the original request of the invoice.

Rate limits

CodeHTTPMeaningWhat to do
—429Your organization sent too many requests to this path in one minute.Wait, then try again with exponential backoff.
  • The body has an error field, for example "error": "Rate limit exceeded: 60 per 1 minute".
  • The response has no Retry-After header.
  • When you send a submission again, use the same Idempotency-Key.

For the limit of each path, refer to Rate limits.