Errors and Refusal codes

Every error the Essentio Public API answers has one shape, whatever went wrong and whatever the request asked to be answered in. A program branches on the error’s type, and on a refused Action’s Refusal code; the message is for a person.

The error shape

An error is a JSON object with one field, error:

  • Name
    type
    Type
    string
    Description

    What kind of error it is — one of the error types. Branch on this.

  • Name
    message
    Type
    string
    Description

    What went wrong, in words for a person, in the words Essentio’s own screens use.

  • Name
    errors
    Type
    object
    Description

    With a 422 invalid_request whose fields the rules refused: each field, parameter or header at fault, with a list of what is wrong with it.

  • Name
    code
    Type
    string
    Description

    With a refusal: the Refusal code that says why.

  • Name
    remedy
    Type
    string
    Description

    With some refusals: what the Business does in Essentio to open the Action — one of the remedies.

  • Name
    document_number
    Type
    string
    Description

    When a Send issued its Draft and then did not go out (not_delivered, or the refusal mail_account_lost): the Document number the Draft took. It stays issued.

  • Name
    invoice
    Type
    object
    Description

    With the remedy record_on_its_invoice: id and document_number of the Invoice that takes the Payment instead.

A Client with no email: 422

{
  "error": {
    "type": "invalid_request",
    "message": "The email field is required.",
    "errors": {
      "email": ["The email field is required."]
    }
  }
}

A 4xx answer means the request changed nothing in the Business, with one exception: a Send that issued its Draft and then found the mail account lost (mail_account_lost) keeps the Draft issued, and says so in document_number — as a 502 not_delivered after an issue does.

Error types

The types an answer carries today. Within v1 another may be added (see Versioning): treat a type you do not know by its HTTP status.

  • Name
    authentication
    HTTP status
    401
    Description

    The request carries no API key or access token, an unknown one, or one that no longer acts: a revoked key, an expired token, or a Connected app that ended. See Authentication.

  • Name
    permission
    HTTP status
    403
    Description

    The credential’s Role may not do this: an API key’s, or the Role a Connected app acts with now — or the Business’s plan does not let it, and then code says why. It is asked before the record the request names, so a Role that may not make a change is answered permission whatever id it sends, one that names nothing included.

  • Name
    not_found
    HTTP status
    404
    Description

    No such endpoint, or the Business has no record with this id. A record of another Business is not found either.

  • Name
    invalid_request
    HTTP status
    4xx
    Description

    Any other request the API cannot answer as sent. A 422 names each field, parameter or header at fault in errors, in the words Essentio’s own forms use — a decimal sent as a JSON number, a limit out of range, a cursor the API did not give.

  • Name
    idempotency
    HTTP status
    422
    Description

    An Idempotency-Key sent again with another request than the first one under it. Nothing was done. See Idempotency.

  • Name
    idempotency_in_flight
    HTTP status
    409
    Description

    The first request under this Idempotency-Key is still being performed. Nothing was done; send the same request again in a few seconds to read its answer.

  • Name
    rate_limit
    HTTP status
    429
    Description

    The API key or Connected app made more requests this minute than its limit allows. Nothing was done; wait Retry-After seconds. See Rate limits.

  • Name
    refusal
    HTTP status
    422
    Description

    The Action is refused for the document or Payment as it stands. code says why; nothing was written.

  • Name
    not_delivered
    HTTP status
    502
    Description

    The mail provider did not accept a Send’s email, or could not be reached in time. The request was sound.

  • Name
    server_error
    HTTP status
    5xx
    Description

    A fault on Essentio’s side.

Refused, not permitted, not delivered

Three errors answer a request that was well formed, and each asks something different of your program:

  • refusal (422): the Business’s rules refuse the Action for the record as it stands — an issued document is not issued again, a Draft is not cancelled, a Client with no email address is not sent a document. The same request stays refused until the record changes. Read code, and remedy when there is one.
  • permission (403): the credential’s Role may not take the Action at all — a Viewer’s key sending a document. No change to the document opens it; a credential with another Role does. A Role that may not take an Action is never answered as a refusal. The Public API itself needs a paid plan: while the Business is on the Free plan or Paused, every request of its API keys and Connected apps is this failure with the code paid_plan_required and the remedy choose_plan, a read included, and the same credential works again once the Business is paid. The MCP server works on every plan; there, when the Business’s plan is why a change is refused — it is Paused, or on the Free plan — the failure carries its code (business_paused, plan_role_viewing) and the remedy choose_plan. A plan chosen in Essentio opens either.
  • not_delivered (502): the Send was allowed and tried, and the mail provider did not take it. The same request may succeed later. When the connection to the provider failed, the email may have gone out before it dropped, so check before you send again.

A document says beforehand what each Action would answer: its actions hold, for issue, send, cancel, convert, record_payment and delete, whether the Action is open and, when it is not, the Refusal code it would answer — or role_forbidden when your credential’s Role may not take it. Read them to draw only the buttons that would work.

Refusal codes

Why an Action is refused. The same refusal always has the same code, and within v1 codes are only added — never renamed or removed. Read a code you do not know as a refusal you do not handle yet, and show its message. The list holds every code Essentio has: first the ones the API’s operations answer, then the ones Essentio answers only in its own screens, on the MCP server, or to a caller that met none of the API’s rules — listed so that one never surprises you.

  • Name
    already_issued
    Refused by
    Issue
    Description

    Only a Draft is issued; this document already has its number.

  • Name
    number_taken
    Refused by
    Issue, or a Send that issues a Draft
    Description

    The Document number the Draft asks for (requested_document_number) is already taken by another document.

  • Name
    number_skips_ahead
    Refused by
    Issue, or a Send that issues a Draft
    Description

    The requested number skips ahead of the numbering; message names the next one.

  • Name
    number_beyond_the_counter
    Refused by
    Issue, or a Send that issues a Draft
    Description

    The requested number ends in a number larger than the numbering can count to.

  • Name
    number_malformed
    Refused by
    Issue, or a Send that issues a Draft
    Description

    The requested number is not a valid Document number.

  • Name
    numbering_at_its_end
    Refused by
    Issue, a Send that issues a Draft, or Record a Payment
    Description

    The next number — a document's, or a Receipt's — is the largest the numbering holds, which it never takes, because it cannot count past it; message names that number. Nothing is written. A Draft can still be issued with an unused earlier number sent as its document_number; a Receipt has no such way out.

  • Name
    cancelled_not_sent
    Refused by
    Send
    Description

    A Cancelled document is not sent.

  • Name
    no_client_address
    Refused by
    Send
    Description

    The Client has no email address. Nothing is issued.

  • Name
    no_mail_provider
    Refused by
    Send
    Description

    The Business has nothing to send through: it sends through Essentio's own mail server unless it connected a mailbox, and it has no email address of its own for replies (remedy connect_mail_provider). Nothing is issued.

  • Name
    mail_account_lost
    Refused by
    Send
    Description

    The Business’s connected mail account refused to renew its access (remedy connect_mail_provider).

  • Name
    sending_limit_reached
    Refused by
    Send
    Description

    The Business sends through Essentio's own mail server, which emails a limited number of recipients for it a day — To, Cc and Bcc each count: 20 on the Free plan, a Test business and a Paused Business, 100 on Pro, 200 on Pro Plus — and this email does not fit what is left; message says how many are (remedy connect_mail_provider: its own mailbox has no such limit). Once none is left a Draft is not issued; a Send refused after it issued its Draft names the number in message.

  • Name
    draft_not_cancelled
    Refused by
    Cancel
    Description

    A Draft is not a document yet; it is deleted instead (DELETE /v1/documents/{id}).

  • Name
    paid_not_cancelled
    Refused by
    Cancel
    Description

    A Paid document is corrected with a Credit Note.

  • Name
    already_cancelled
    Refused by
    Cancel
    Description

    The document is already Cancelled.

  • Name
    holds_money
    Refused by
    Cancel
    Description

    The document holds Payments (or its Proforma’s); it is corrected with a Credit Note.

  • Name
    not_a_proforma
    Refused by
    Convert
    Description

    Only a Proforma Invoice converts into an Invoice.

  • Name
    draft_not_converted
    Refused by
    Convert
    Description

    A Draft Proforma Invoice is issued first.

  • Name
    cancelled_not_converted
    Refused by
    Convert, or Update a document
    Description

    A Cancelled Proforma Invoice converts into nothing, so neither is it converted nor is a Draft still linked to it saved, which would issue it.

  • Name
    already_converted
    Refused by
    Convert
    Description

    An Invoice was already made from this Proforma Invoice.

  • Name
    issued_not_deleted
    Refused by
    Delete
    Description

    Only a Draft is deleted; an issued document is cancelled instead.

  • Name
    type_takes_no_payments
    Refused by
    Record or amend a Payment
    Description

    A Credit Note or a Quote takes no Payments; message says why.

  • Name
    draft_takes_no_payments
    Refused by
    Record or amend a Payment
    Description

    A Draft is issued first.

  • Name
    cancelled_takes_no_payments
    Refused by
    Record or amend a Payment
    Description

    A Cancelled document takes none.

  • Name
    nothing_due
    Refused by
    Record a Payment
    Description

    The document’s Amount due is zero.

  • Name
    payment_goes_to_its_invoice
    Refused by
    Record a Payment
    Description

    The Proforma Invoice was converted into an Invoice, which takes the Payment (remedy record_on_its_invoice with error.invoice, while that Invoice still takes one).

  • Name
    payment_currency_mismatch
    Refused by
    Record or amend a Payment
    Description

    currency is not the document’s.

  • Name
    payment_exceeds_amount_due
    Refused by
    Record or amend a Payment
    Description

    The amount is above what is due.

  • Name
    payment_reversed
    Refused by
    Amend or reverse a Payment
    Description

    It was reversed already.

  • Name
    issued_not_changed
    Refused by
    Update a document
    Description

    Only a Draft is changed through the API; an issued document is changed in Essentio.

  • Name
    draft_deleted
    Refused by
    Issue, Send, or Update a document
    Description

    The Draft was deleted meanwhile, by another request made while this one waited for it. Nothing is written and no number is taken.

  • Name
    proforma_deleted
    Refused by
    Update a document
    Description

    The Draft is linked to a Proforma Invoice that was deleted, so nothing is converted from it and its save, which would issue it, is refused.

  • Name
    only_into_an_invoice
    Refused by
    Update a document
    Description

    The Draft is linked to a Proforma Invoice, and only an Invoice is made from one.

  • Name
    proforma_other_currency
    Refused by
    Update a document
    Description

    The Draft is linked to a Proforma Invoice in another currency; message names it.

  • Name
    proforma_other_client
    Refused by
    Update a document
    Description

    The Draft is linked to a Proforma Invoice of another Client.

  • Name
    not_exportable
    Refused by
    Download a document’s XML
    Description

    The document is not exported as EN16931 XML (a Draft, a Proforma Invoice, a Quote, or one the EN16931 check does not pass); message says why.

  • Name
    exports_not_in_a_test_business
    Refused by
    Download a document’s XML
    Description

    The Business is a Test business (is_test), which keeps no real books, so it exports nothing an accountant books from. Its PDFs stay, marked SAMPLE.

  • Name
    role_forbidden
    Where
    in a document’s actions only
    Description

    The credential’s Role may not take the Action. Taken anyway, it is a permission failure (403), not a refusal.

  • Name
    paid_plan_required
    Refused by
    Any request
    Description

    The Business is on the Free plan or Paused, and the Public API needs a paid plan, so every API key and Connected app of the Public API is refused whatever it asks, a read included. It is a permission failure (403) carrying this code and the remedy choose_plan; message says whether the Business is on the Free plan or paused. Nothing is revoked: the same credential works again once the Business is on Pro or Pro Plus. It comes before any other answer, so the Public API never answers business_paused or plan_role_viewing.

  • Name
    business_paused
    Refused by
    Any change the plan does not keep, on the MCP server and in Essentio
    Description

    The Business is Paused, because its Owner’s plan does not cover it; it still reads everything and records Payments. Taken, it is a permission failure (403) carrying this code and the remedy choose_plan; a document’s actions answer it too. The Public API refuses a Paused Business’s credentials paid_plan_required first.

  • Name
    plan_role_viewing
    Refused by
    Any change, on the MCP server and in Essentio
    Description

    The Business is on the Free plan, where everyone but its Owner only reads, and so does every Connected app they authorised; the Owner’s own Connected app is cut by nothing but the Role it was given. Taken, it is a permission failure (403) carrying this code and the remedy choose_plan; a document’s actions answer it too. The Public API refuses a Free Business’s credentials paid_plan_required first.

  • Name
    not_a_member
    Refused by
    Any Action, in Essentio
    Description

    The document is another Business’s. On the API another Business’s record is not_found (404).

  • Name
    issuing_limit_reached
    Refused by
    Issue, or a Send that issues a Draft
    Description

    The Business is on the Free plan, or is a Test business, and has issued its Invoices for this year; message names the day it issues again (remedy choose_plan). On the MCP server only a Free Business’s Owner’s own Connected app issues, so it meets this; anyone else’s meets plan_role_viewing first, and the Public API answers a Free Business paid_plan_required first. A Test business keeps the Public API on every plan and meets it there too, in its own words and with no remedy: a reset lets it issue again.

  • Name
    no_mail_provider_to_remind
    Refused by
    Remind, in Essentio
    Description

    The Business has nothing to send through — no mailbox connected and no email address of its own for Essentio's mail (remedy connect_mail_provider).

  • Name
    not_remindable
    Refused by
    Remind, in Essentio
    Description

    Reminders go only for issued documents still unsettled.

  • Name
    never_reminded
    Refused by
    Remind, in Essentio
    Description

    A Credit Note or a Quote is never reminded about; message says why.

  • Name
    converted_proforma
    Refused by
    Remind, in Essentio
    Description

    The Proforma Invoice was converted into an Invoice, which is reminded about instead.

  • Name
    receipt_voided
    Refused by
    Email a Receipt, in Essentio
    Description

    The Payment was reversed, so its Receipt is void.

  • Name
    no_mail_provider_for_receipt
    Refused by
    Email a Receipt, in Essentio
    Description

    The Business has nothing to send through — no mailbox connected and no email address of its own for Essentio's mail (remedy connect_mail_provider).

  • Name
    no_receipt
    Refused by
    Email a Receipt, in Essentio
    Description

    The Payment has no Receipt.

  • Name
    client_deleted
    Refused by
    Duplicate, in Essentio
    Description

    The document’s Client was deleted.

  • Name
    payment_not_positive
    Refused by
    Record or amend a Payment, in Essentio
    Description

    The amount is not above zero. The API refuses that amount as invalid_request first.

  • Name
    payment_not_in_minor_units
    Refused by
    Record or amend a Payment, in Essentio
    Description

    The amount is finer than its currency’s minor unit. The API refuses that amount as invalid_request first.

  • Name
    cancelled_not_edited
    Refused by
    Edit, in Essentio
    Description

    A Cancelled document is not edited.

  • Name
    number_not_correctable
    Refused by
    Correct a Document number, in Essentio
    Description

    The document takes no correction of its number as it stands.

  • Name
    proforma_not_found
    Refused by
    Save a document linked to a Proforma Invoice
    Description

    The Proforma Invoice it names is not found.

  • Name
    draft_not_delivered
    Refused by
    Mark sent, in Essentio
    Description

    A Draft is issued first.

  • Name
    cancelled_not_marked
    Refused by
    Mark sent, in Essentio
    Description

    A Cancelled document is not marked as sent.

  • Name
    cancelled_keeps_mark
    Refused by
    Unmark sent, in Essentio
    Description

    A Cancelled document keeps its delivery mark.

  • Name
    not_marked_sent
    Refused by
    Unmark sent, in Essentio
    Description

    The document is not marked as sent.

  • Name
    webhook_paused
    Refused by
    Resend a Webhook delivery, in Essentio
    Description

    The Webhook is paused.

  • Name
    app_not_connected
    Refused by
    Resend a Webhook delivery, in Essentio
    Description

    The app no longer hears the Business the message is about.

  • Name
    webhooks_need_a_paid_plan
    Refused by
    Resend a Webhook delivery, in Essentio
    Description

    The Business the message is about is on the Free plan or Paused, and Webhooks need a paid plan.

  • Name
    support_read_only
    Refused by
    Any change, in Essentio
    Description

    The request is Essentio support’s, which reads a Business with its Owner’s Support access and changes nothing. No credential of the API or the MCP server is support’s.

A number the Draft asks for that is taken, skips ahead or is malformed leaves the Draft a Draft: change or clear its document_number and try again. Each resource’s page says which codes its Actions answer: documents and Payments. These words are the contract’s own: RefusalCode in the OpenAPI file.

Remedies

What the Business does in Essentio to open a refused Action. It is nothing an API call can do: show it to a person who can act in Essentio. Remedies, too, are only added within v1. A document’s actions carry remedy_url, the page in Essentio, for connect_mail_provider and choose_plan.

  • Name
    connect_mail_provider
    Description

    In Settings → Email, connect a mailbox of the Business's own (or connect the lost account again); for no_mail_provider, adding the Business's email address in Settings → General lets Essentio send again, and for sending_limit_reached the next day does.

  • Name
    record_on_its_invoice
    Description

    The Proforma Invoice was converted into an Invoice, which carries the debt: record the Payment on that Invoice (error.invoice) instead.

  • Name
    choose_plan
    Description

    The Business’s plan does not let it (business_paused, plan_role_viewing, paid_plan_required, webhooks_need_a_paid_plan, issuing_limit_reached): its Owner chooses a plan in Settings → Billing.

Handling an error

Branch on the HTTP status and type first, and on code for a refusal. This cancels a document and, when it turns out to be a Draft — which is deleted, not cancelled — deletes it instead:

Cancel a document, or delete it if it is a Draft

answer=$(curl -s -X POST https://api.essentio.pro/v1/documents/118/cancel \
  -H "Authorization: Bearer $ESSENTIO_API_KEY")

case "$(echo "$answer" | jq -r '.error.code // empty')" in
  "") echo "Cancelled: $(echo "$answer" | jq -r .status)" ;;
  draft_not_cancelled)
    curl -s -X DELETE https://api.essentio.pro/v1/documents/118 \
      -H "Authorization: Bearer $ESSENTIO_API_KEY"
    echo "It was a Draft: deleted" ;;
  *) echo "Refused: $(echo "$answer" | jq -r .error.message)" ;;
esac

Cancelling a Draft: 422

{
  "error": {
    "type": "refusal",
    "code": "draft_not_cancelled",
    "message": "A draft is deleted, not cancelled — it is not a document yet."
  }
}