Invoicing Flow

Summary

This page shows the invoicing leg of the Vertex API flow: how a client submits an invoice and
gets back a compliant e-invoice, once tax amounts are already known. Applies across Vertex's LatAm coverage:
The endpoints, call types, and webhook contract are the same regardless of country; only the
payload fields and the local tax authority differ.

Key things to know before reading the diagram:

  1. Invoices are issued one by one, not in bulk. Each POST /invoices call submits exactly
    one invoice. There is no batch-submission endpoint — if you need to issue 500 invoices, that's
    500 separate calls.
  2. Your systems always initiate the request. Vertex only calls you back once, via webhook, to
    confirm the outcome.
  3. The webhook — not the sync response to POST /invoices — is what tells you whether the
    invoice actually succeeded. The sync response only confirms the request was well-formed.
  4. You can implement a polling fallback. If by any change you don't receive the webhook, poll GET /invoices/{invoice_id} until the invoice reaches a final status. See If the webhook doesn't arrive.

Call sequence

sequenceDiagram
    autonumber
    participant Client
    participant Vertex
    participant Auth as Tax Authority

    Client->>Vertex: POST /invoices
    Vertex-->>Client: 201 status "received" / 400-500 schema error

    rect rgba(168,118,15,0.08)
    Note over Vertex,Auth: async backend — no client-facing call
    Vertex->>Auth: transmit invoice to the local tax authority
    Auth-->>Vertex: accept / reject
    end

    rect rgba(46,125,82,0.09)
    Note over Client,Vertex: Scenario: created invoice
    Vertex--)Client: webhook — status: created
    Client->>Vertex: GET /invoices/{invoice_id}
    Vertex-->>Client: invoice_key, documents, country fields
    end

    rect rgba(178,58,58,0.09)
    Note over Client,Vertex: Scenario: failed invoice
    Vertex--)Client: webhook — status: failed
    end

Every call above the shaded amber band is client-initiated and synchronous. Inside that band,
Vertex talks to the local tax authority with no client visibility. The webhook is the only call
Vertex initiates, and it always carries one of exactly two outcomes — created or failed —
shown above as two mutually exclusive scenarios. created ends after the GET in step 5;
failed ends at the webhook itself.


If the webhook doesn't arrive

The webhook is the primary way to learn an invoice's outcome, but your integration should not
depend on it alone. If the webhook hasn't arrived after the expected time, implement a
short-polling fallback: call GET /invoices/{invoice_id} on an interval until the invoice
reaches a final status.

How it works

  1. Store the id returned in the 201 response of POST /invoices (or use your own
    invoice_external_id with ?use_external_id=true).
  2. Wait for the webhook. If it arrives, stop: no polling needed.
  3. If it hasn't arrived after the initial wait for that country, call
    GET /invoices/{invoice_id} and check status:
statusMeaningWhat to do
receivedStill being processed by the tax authority.Not final. Wait and poll again.
createdAccepted by the tax authority.Final. Use invoice_key, pdf_url / xml_url and country fields from this same response. Stop polling.
failedRejected by the tax authority.Final. Read the errors, fix the payload, and submit a new invoice. Stop polling.
  1. Keep polling with increasing intervals (backoff) until you get created or failed, or
    until you reach your maximum wait time. If the invoice is still received after that,
    contact Vertex support with the invoice_id.

Best practices

  • Don't resubmit while received. Sending the same invoice again with POST /invoices
    can create a duplicate document at the tax authority. Only submit a new invoice after a
    failed status.
  • Polling is a fallback, not a replacement. Keep the webhook as your main signal; poll
    only for invoices whose webhook hasn't arrived in time.

Example

curl --request GET \
  --url https://api.brinta.com/invoices/36bc8191-3011-41ec-8e0b-2c00462ad955 \
  --header 'Authorization: Bearer <token>'

Still processing:

{
  "id": "36bc8191-3011-41ec-8e0b-2c00462ad955",
  "invoice_external_id": "53987482cdvjb48h",
  "status": "received",
  "status_description": "The invoice request has been received."
  "..."
}

Final (accepted):

{
  "id": "36bc8191-3011-41ec-8e0b-2c00462ad955",
  "invoice_external_id": "53987482cdvjb48h",
  "status": "created",
  "status_description": "The invoice is created.",
  "invoice_key": "75452644088340",
  "pdf_url": "https://...",
  "..."
}

Step reference

endpoints as called against api.brinta.com

#EndpointDirectionTypeNotes
1POST /invoicesClient → VertexSYNCSubmit invoice. Sync response is a schema check only: valid → status: received (201); invalid → 400/500.
2—Vertex → Tax AuthorityASYNCVertex transmits the invoice to the local tax authority.
3—Tax Authority → VertexASYNCAuthority accepts or rejects.
4WebhookVertex → ClientWEBHOOKThe only call Vertex initiates. Payload: invoice_id, invoice_external_id, status. 2 possible outcomes: created (tax authority accepted) or failed (rejected). For rejected invoices, errors will be sent in the webhook body
5GET /invoices/{invoice_id}Client → VertexSYNCOnly when step 4's status is created — a failed webhook is terminal, there's nothing to fetch. Works with invoice_id, or with invoice_external_id by adding ?use_external_id=true (docs). Returns invoice_key, documents (PDF/XML or country equivalent), and country-specific fields.

If invoice_external_id is used, then use param array=true to return an array of every invoice with that invoice_external_id (maximum 20) instead of one invoice.


Vertex API · api.brinta.com — request examples: Postman collection


Did this page help you?