Factuarea APIDevelopers

Events

Read-only event objects with an opaque id. Historical query via the API and webhook delivery.

Every event published in Factuarea is persisted as a read-only event object with an opaque id (a UUID v7, e.g. 01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0d), consistent with the id of every other v1 resource. This lets you:

  • Query it via API: GET /v1/companies/{company}/events/{id} and GET /v1/companies/{company}/events?type=invoice.paid.
  • Deliver it to subscribed webhook endpoints, in a signed envelope with the same id, type and data (see Webhooks).
  • Replay a delivery from the dashboard (Developers > Webhooks > Deliveries).

Payload shape

GET /v1/companies/{company}/events/{id} returns the event under data. The event looks like this, with the invoice under data.object abridged to six of its fields:

{
  "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0d",
  "object": "event",
  "type": "invoice.paid",
  "aggregate_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a42",
  "correlation_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a99",
  "api_version": "2026-09-23",
  "livemode": true,
  "test": false,
  "data": {
    "type": "invoice.paid",
    "object": {
      "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a42",
      "object": "invoice",
      "number": "FAC-2026-00042",
      "status": "paid",
      "total": "1210.00",
      "currency": "EUR"
    },
    "amount": "1210.00",
    "payment_date": "2026-03-20",
    "payment_method": "bank_transfer",
    "payment_reference": "TRF-2026-0042"
  },
  "created": 1774002600
}

Fields:

  • id — opaque identifier of the event (UUID v7). Use it to deduplicate on your side.
  • object — always event.
  • type — event name as <category>.<action> (e.g. invoice.paid, quote.approved).
  • aggregate_id — UUID v7 of the resource that produced the event (e.g. the invoice for invoice.paid). null for events without a backfilled aggregate. Distinct from id, which identifies the event itself.
  • correlation_id — UUID v7 that links the events caused by one operation, or null when there is none. The key is always present.
  • api_version — date-based version the payload was serialized under, sealed at emission. Always present on events emitted today; null only for legacy events emitted before versions were sealed.
  • livemode — true for events generated in production (live key, fact_live_); false for events generated in test mode (sandbox company, fact_test_ key). Test-mode events are recorded and queryable via GET /v1/companies/{company}/events, but not delivered to webhook endpoints (see Test mode & sandbox), so any event your endpoint actually receives is always livemode: true.
  • test — true for a test delivery sent with test-event, false for real events. It is orthogonal to livemode.
  • data — { "type", "object" }. object is the full snapshot of the affected resource as it was when the event happened, identical to what a GET of that resource returned at that moment. It is frozen: later changes to the resource don't rewrite past events, so fetch the resource from its own endpoint when you need its current state. The keys that are specific to the event sit next to object, such as amount and payment_date in invoice.paid.
  • created — Unix timestamp, in seconds, of when the event was created.

A webhook delivers the same event in a signed envelope: the same id, type, api_version, created, livemode, test, correlation_id and data, without object and aggregate_id. See its delivery body.

Idempotency

Each event has a unique id. Webhooks redeliver the same id to the same endpoint on every retry, and an account endpoint that admits the same event of a tax ID receives it with the same id too. In your handler, store the ids you have processed and answer 2xx without acting if you see one again. Deduplicate webhook deliveries has the whole recipe and how long to keep the ids.

Event catalog

The full, authoritative catalog of subscribable event types is returned by GET /v1/event-catalog. Each entry carries a name, a category, a human-readable description, and a status (available or coming_soon):

curl https://api.factuarea.com/v1/event-catalog \
  -H "Authorization: Bearer $FACTUAREA_API_KEY"
{
  "data": [
    {
      "name": "invoice.paid",
      "category": "invoice",
      "description": "Factura pagada",
      "status": "available"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

This is the catalog of the events of a tax ID. The account.* events of the account itself are not in it: see Account events.

Representative event types by category (query the catalog for the complete, up-to-date list):

Invoices

invoice.created, invoice.auto_created, invoice.corrective_auto_created, invoice.subscription_auto_created, invoice.updated, invoice.issued, invoice.marked_sent, invoice.unsent, invoice.sent (deprecated), invoice.paid, invoice.cancelled, invoice.annulled, invoice.overdue, invoice.deleted, invoice.number_assigned, invoice.rectified, invoice.email_sent, invoice.email_failed, invoice.payment_reminder_sent, invoice.simplified_created, invoice.simplified_substituted, invoice.substituted_by_complete, invoice.verifactu_submitted, invoice.verifactu_failed, invoice.metadata_changed.

invoice.auto_created / invoice.corrective_auto_created / invoice.subscription_auto_created are emitted by the payment-gateway auto-invoicing flows when a charge, refund or subscription cycle produces an invoice automatically.

invoice.issued is emitted when an invoice is issued: definitive number, VeriFactu record and stock movements. invoice.marked_sent is emitted when it reaches the customer (the mail server accepted its delivery email, or someone marked it by hand) and invoice.unsent when that mark is cleared. A payment never marks an invoice as sent. invoice.sent is a deprecated alias of invoice.issued, emitted at the same instant with the same data.object; new integrations should subscribe to invoice.issued, and the removal of the alias will be announced with a Sunset date. Automation rules no longer accept invoice.sent as a trigger.

Quotes

quote.created, quote.updated, quote.deleted, quote.approved, quote.rejected, quote.converted, quote.expired, quote.marked_as_pending, quote.cancelled, quote.number_assigned, quote.metadata_changed, quote.email_sent, quote.email_failed.

Pro-forma invoices

proforma.created, proforma.updated, proforma.deleted, proforma.accepted, proforma.rejected, proforma.cancelled, proforma.expired, proforma.converted_to_invoice, proforma.number_assigned, proforma.metadata_changed, proforma.email_sent, proforma.email_failed.

Delivery notes

delivery_note.created, delivery_note.updated, delivery_note.status_changed, delivery_note.signed, delivery_note.converted, delivery_note.email_sent, delivery_note.email_failed.

Transport control documents

transport_document.created, transport_document.updated, transport_document.issued, transport_document.modified, transport_document.closed, transport_document.reopened, transport_document.cancelled, transport_document.superseded, transport_document.email_sent, transport_document.email_failed.

Each delivery carries the full v1 transport_document resource under data.object. They are emitted whatever the origin of the change — the app, the REST API, MCP or the daily automatic close. transport_document.updated also fires when a draft copies again a party whose contact or company data changed (see Transport control document (DeCA)). transport_document.closed tells a manual close from an automatic one with data.object.close_mode (manual or automatic). transport_document.email_sent (the mail server accepted the email) and transport_document.email_failed (it could not be delivered) work like those of delivery notes: next to data.object, data carries recipient_email (the first to address), the to, cc and bcc lists and the version of the PDF attached; email_sent adds transport_document_number and email_failed adds error_message and error_class. Deleting a draft is not published as an event. The transport_document prefix belongs to the transport_documents module. See Transport control documents.

Expenses

purchase_invoice.created, purchase_invoice.updated, purchase_invoice.paid, purchase_invoice.payment_registered, purchase_invoice.cancelled, purchase_invoice.metadata_changed.

Recurring invoices

recurring_invoice.created, recurring_invoice.activated, recurring_invoice.paused, recurring_invoice.updated, recurring_invoice.deleted, recurring_invoice.completed, recurring_invoice.executed, recurring_invoice.failed, recurring_invoice.cancelled, recurring_invoice.metadata_changed.

Clients & products

client.created, client.updated, client.deleted, client.metadata_changed, product.created, product.updated.

Series & taxes

series.created, series.updated, series.deleted, series.archived, series.unarchived, series.marked_as_default, series.demoted_from_default, series.number_consumed, series.year_reset, series.month_reset, tax.metadata_changed, tax.validity_changed, tax.external_reference_changed.

The tax.* events are delivered for the taxes owned by your company. Taxes of the Factuarea catalog do not emit events.

FacturaE (FACe)

facturae.face_submitted, facturae.face_status_changed, facturae.face_cancellation_requested.

Payments & gateways

payment.received, payment.reversed, payout.reconciled.

payment.received and payment.reversed are the two halves of one cycle: the first fires when a payment is registered against an invoice, the second when that payment is voided and the invoice goes back into the collection circuit. Subscribe to both — an invoice you recorded as collected can stop being collected, and reacting only to the first half means trusting a figure that expired. See payment.reversed below.

payout.reconciled fires when a Stripe payout is reconciled against your bank statement (see Payouts & reconciliation).

Automations

automation_rule.activated, automation_rule.paused, automation_rule.auto_paused, automation_run.started, automation_run.completed, automation_run.failed, automation_run.step_dead_lettered.

The engine reports its own life cycle. The three automation_rule.* events carry the rule in the delivery body, under data.object: activated when a rule goes live and starts listening to its trigger, paused when a person stops it, and auto_paused when the platform stops it after a streak of failed runs.

The four automation_run.* events carry the run in the delivery body, under data.object: started when a matched trigger clears the engine limits and the run is admitted, completed when every step applied its effect, failed when the run finished without producing its effect and cannot be reprocessed, and step_dead_lettered when a single step is parked awaiting a manual replay. As everywhere else, data.object is the snapshot taken when the event was emitted, not the current state of the resource. See the run reference.

Two of them carry extra keys beside the snapshot. automation_rule.auto_paused adds consecutive_failures, the number of consecutive failed runs that tripped the automatic pause — the platform paused the rule, and automation_rule.paused is its human counterpart. automation_run.step_dead_lettered adds step_index and discard_reason: step_index is the zero-based position of the parked step, resolved against the snapshot itself (the element of data.object.steps whose step_index matches, because a step is not a public resource of its own), and discard_reason is a typed value from a closed catalog, never free-form text. In practice it is always a replayable reason: an outcome that does not admit reprocessing closes the run as failed instead of parking the step.

These seven names live in the same closed catalog as every other event, so they are valid rule triggers too: an automation can react to automation_run.failed exactly as it reacts to invoice.paid, and no exclusion list hides them from the trigger catalog. Like the rest of the engine, they are gated by the automations module.

Chaining them is bounded, not forbidden. Every hop "action → event → rule" consumes the engine's chain-depth cap — three hops by default — so a rule that reacts to automation_run.failed and fails again cannot loop forever: once the cap is spent the run is not executed, it is recorded as blocked. An event produced by a person or by an integration enters at depth zero, so only what an automation itself caused spends that budget.

Tasks & projects

The task module publishes 21 events in four families. They live in the same closed catalog as every other event, so a webhook endpoint can subscribe to them (or to "*"), and they are valid automation triggers for companies with the tasks module — a company without it neither sees them in the trigger catalog nor can save a rule that uses one.

FamilyEvents
Taskstask.created, task.updated, task.deleted, task.status_changed, task.completed, task.assigned, task.unassigned, task.moved, task.due_soon, task.overdue
Commentstask_comment.created, task_comment.updated, task_comment.deleted
Logged timetask_time_entry.created, task_time_entry.updated, task_time_entry.deleted, task_time_entry.invoiced
Projectsproject.created, project.updated, project.archived, project.deleted

Every event is emitted by the operation that causes it, from any surface — the app, the API, MCP, the employee portal, an automation, an integration or a scheduled process — and is delivered once per fact, even if the event is redelivered internally.

EventEmitted whenExtra keys beside object
task.createdA task is created, also by duplicating, importing or an automation—
task.updatedThe title, description, priority, start_on or due_on changechanged_fields
task.deletedA task is deleted, also in bulkproject_id
task.status_changedThe column or the virtual status (planned, active, archived) changesprevious_status, previous_column_id
task.completedThe task enters a final column—
task.assignedThe task gets an assignee or changes itprevious_assignee_id
task.unassignedThe task loses its assignee—
task.movedThe task moves to another projectfrom_project_id
task.due_soonThe task enters its due-date warning window, once per task and date—
task.overdueThe task passes its due date without being completed, once per task and date—
task_comment.created, .updated, .deletedA comment is created (also one synchronized from a code forge), edited or deletedproject_id, and task_id on .deleted
task_time_entry.created, .updated, .deletedA time entry is created (by hand or by starting a timer), changed (also when a timer stops) or deletedproject_id, and task_id on .deleted
task_time_entry.invoicedA time entry is invoiced: one event for each entry of the batchproject_id
project.created, .updated, .archived, .deletedA project is created, changed (also when it is unarchived), archived or deleted—

What to know when you consume them:

  • data.object is the v1 resource as it was when the event was emitted — a task, task_comment, task_time_entry or project, exactly as the API serializes it (see Projects and tasks) — not the current state. The extra keys of the table travel beside it, under data.
  • task.completed is a subset of task.status_changed. Moving a task into a final column emits both. Subscribe to task.status_changed to follow every move between columns and states, and to task.completed only if completions are all you care about; subscribing to both delivers two events for one completion.
  • Deletions degrade. task.deleted, task_comment.deleted, task_time_entry.deleted and project.deleted carry deleted: true in data.object and, when the resource can no longer be read, nothing but its id. Their sibling project_id (and task_id) still tells you where it was.
  • Route by project. Every task, comment and time event carries the id of its project — in data.object.project_id, or in data.project_id when the object has none or the event is a deletion. For project.* events the project is data.object.id. See the webhooks guide for a handler.
  • Unarchiving is an update. There is no project.unarchived: unarchiving a project emits project.updated.
  • task.due_soon and task.overdue fire once per task and due date. Changing the due date arms both again for the new date.
  • Logged time is not the working-day register. The prefix is task_time_entry, never time_entry, which belongs to the clock-ins of Time tracking; a company without that module still receives task_time_entry.*. See Time logged on tasks.

Account events

Besides the events of a tax ID above, there are seventeen account events, with names that start with account.. They tell you what happens to the account itself: its members and owner (account.member_added, account.owner_transferred…), the access it gives to other accounts (account.access_granted…), the accounts it manages (account.managed_account_provisioned…), its tax IDs coming and going (account.nif_added, account.nif_transferred, account.nif_archived), its bulk imports (account.import_completed), its contracted seats (account.seats_updated) and the end of an offer package (account.offer_package_ended). Their audience is the account, not a tax ID, so they live apart from everything else on this page:

  • They are not in the company event catalog. GET /v1/event-catalog doesn't list them, and a company endpoint can't subscribe to them: an account.* name in its enabled_events answers 422 and nothing is created. They are not in the event log of GET /v1/companies/{company}/events either, because that log belongs to one tax ID.
  • They don't trigger company automations. The catalog of triggers of the automations is built from the company events, so an account.* event is never the trigger of a rule.
  • They only reach account endpoints. Only an account webhook endpoint can subscribe to them, together with the company events if you want. Its account_relationship filter and the family of each event decide who hears it.

Account webhooks lists the seventeen names with the data.object of each, the envelope an account endpoint receives and who hears each event. An event of a tax ID, such as invoice.paid, can reach an account endpoint too, and it keeps the same id it has at a company endpoint: see Deduplicate webhook deliveries.

Payload examples

These are the bodies that a webhook delivers, with data.object abridged to a few fields: the real one is the whole resource, as in Payload shape.

invoice.paid

{
  "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0d",
  "type": "invoice.paid",
  "api_version": "2026-09-23",
  "created": 1774002600,
  "livemode": true,
  "test": false,
  "correlation_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a99",
  "data": {
    "type": "invoice.paid",
    "object": {
      "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a42",
      "object": "invoice",
      "number": "FAC-2026-00042",
      "status": "paid",
      "total": "1210.00",
      "currency": "EUR"
    },
    "amount": "1210.00",
    "payment_date": "2026-03-20",
    "payment_method": "bank_transfer",
    "payment_reference": "TRF-2026-0042"
  }
}

invoice.issued

The delivery body carries the full invoice under data.object; the example keeps only the fields of the issuance and delivery axes. An endpoint whose api_version is 2026-05-22 receives the same snapshot in the previous vocabulary: "status": "sent", sent_at equal to the issuance instant and no issued_at, sent_via or is_sent. See Webhooks.

{
  "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a7a",
  "type": "invoice.issued",
  "api_version": "2026-10-01",
  "created": 1773575100,
  "livemode": true,
  "test": false,
  "correlation_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a7b",
  "data": {
    "type": "invoice.issued",
    "object": {
      "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a03",
      "object": "invoice",
      "number": "FAC-2026-00042",
      "status": "issued",
      "issued_at": "2026-03-15T11:45:00Z",
      "sent_at": null,
      "sent_via": null,
      "is_sent": false
    }
  }
}

transport_document.closed

Emitted when a transport control document is closed. The daily process closes it automatically 7 days after the end of its last transport date (Europe/Madrid); the example is that automatic close. The delivery body carries the full resource under data.object; the example keeps only the lifecycle fields.

{
  "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f9b01",
  "type": "transport_document.closed",
  "api_version": "2026-10-01",
  "created": 1791929700,
  "livemode": true,
  "test": false,
  "correlation_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f9b02",
  "data": {
    "type": "transport_document.closed",
    "object": {
      "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f9a01",
      "object": "transport_document",
      "number": "DC-2026-042",
      "status": "closed",
      "public_url": "https://app.factuarea.com/api/public/deca/q3VfN2mX8yPbK1rT4wZs6LcH0dGjAe9uIoRtYvBnMkE",
      "current_version": 2,
      "closed_at": "2026-10-13T22:15:00+00:00",
      "close_mode": "automatic",
      "reopen_deadline": null,
      "retention_until": "2027-10-13T22:15:00+00:00"
    }
  }
}

client.updated

{
  "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a1a",
  "type": "client.updated",
  "api_version": "2026-09-23",
  "created": 1774003800,
  "livemode": true,
  "test": false,
  "correlation_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a1b",
  "data": {
    "type": "client.updated",
    "object": {
      "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a2b",
      "object": "client",
      "name": "Acme Corporation",
      "tax_id": "B12345674",
      "email": "billing@acme.com"
    }
  }
}

quote.converted

{
  "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a3c",
  "type": "quote.converted",
  "api_version": "2026-09-23",
  "created": 1774003315,
  "livemode": true,
  "test": false,
  "correlation_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a3d",
  "data": {
    "type": "quote.converted",
    "object": {
      "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a04",
      "object": "quote",
      "number": "P-2026-00012",
      "status": "converted",
      "converted_to_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a42"
    },
    "target": "invoice",
    "target_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a42"
  }
}

The snapshot under data.object is the quote as it was when it was converted, and target and target_id point to the invoice that it produced. Fetch that invoice from its own endpoint (e.g. GET /v1/companies/{company}/invoices/{id}) to read its current state.

payment.reversed

Emitted when a payment registered against an invoice is voided. Until it existed, an integration that had heard payment.received had no way of finding out that the same payment had come undone.

Like every event, it carries the affected resource in full under data.object — the payment as the v1 API serialises it, already flagged as reverted — and adds a data.reversal block describing the operation itself:

{
  "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a5e",
  "type": "payment.reversed",
  "api_version": "2026-09-23",
  "created": 1780388100,
  "livemode": true,
  "test": false,
  "correlation_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a6f",
  "data": {
    "type": "payment.reversed",
    "object": {
      "id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a0b",
      "object": "payment",
      "invoice_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a01",
      "amount": "500.00",
      "payment_date": "2026-05-20",
      "payment_method": "direct_debit",
      "payment_method_text": "Domiciliación bancaria",
      "reference": "TRF-2026-0042",
      "notes": null,
      "is_reversed": true,
      "reversed_at": "2026-06-02T08:15:00Z",
      "reversal_reason": "direct_debit_return",
      "reversal_reason_text": "Devolución de adeudo SEPA",
      "reversal_note": "Devuelto por el banco con motivo MD01.",
      "created_at": "2026-05-20T10:30:00Z",
      "updated_at": "2026-06-02T08:15:00Z"
    },
    "reversal": {
      "reason": "direct_debit_return",
      "origin": "gateway"
    }
  }
}
  • data.reversal.reason — one of the five values of the closed catalog: direct_debit_return, card_dispute, misapplied_payment, bounced_effect, recording_error; a sixth, issued_in_error, appears on the payments reverted by annulling an invoice issued by mistake with revert_collections. Branch on this, never on reversal_reason_text, which is a Spanish label for humans.
  • data.reversal.origin — gateway when the payment provider reported a return, dispute or chargeback (money already moved at the bank); manual when a person recorded it. Useful to decide whether to chase the customer or wait for the bank file.

What to do when it arrives: the invoice is back in the collection circuit (issued, sent before API version 2026-10-01, or overdue if its due date has passed) and its paid_amount no longer includes this entry, so refresh whatever you cached about that invoice. Do not issue a corrective invoice as a reaction — a reversal is not a reduction of revenue. See Reversal or corrective invoice?.

task.status_changed

The delivery body carries the task under data.object, as it was after the move, and the two extra keys of this event: the status and the column the task came from. The example keeps only the fields of the board axis.

{
  "id": "0193a4f2-e1a0-7c10-9b21-3d5f7a9c1e01",
  "type": "task.status_changed",
  "api_version": "2026-10-01",
  "created": 1790673330,
  "livemode": true,
  "test": false,
  "correlation_id": "0193a4f2-e1a0-7c10-9b21-3d5f7a9c1e02",
  "data": {
    "type": "task.status_changed",
    "object": {
      "id": "0193a4f2-8f53-7d44-8e85-7a9b1c3d5f16",
      "object": "task",
      "key": "DEV-16",
      "project_id": "0193a4f2-7c20-7a11-8b52-4d6e8f0a2c01",
      "column_id": "0193a4f2-7d31-7b22-8c63-5e7f9a1b3d02",
      "status": "active",
      "title": "Call the customer about the checkout demo",
      "completed_at": null
    },
    "previous_status": "active",
    "previous_column_id": "0193a4f2-7d31-7b22-8c63-5e7f9a1b3d01"
  }
}
  • data.previous_status — planned, active or archived: the board status before the change.
  • data.previous_column_id — the column the task left, or null when it came from the backlog or from the archive.

The other events of the module keep the same envelope: task.assigned adds previous_assignee_id, task.moved adds from_project_id and task.updated adds changed_fields, the list of fields of the public task resource that changed.

Subscribe to events

Via API:

curl -X POST https://api.factuarea.com/v1/companies/{company}/webhook-endpoints \
  -H "Authorization: Bearer $FACTUAREA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://app.mycompany.com/factuarea/webhook",
    "enabled_events": ["invoice.paid", "quote.approved"]
  }'

enabled_events takes event names from the catalog, at least one. A wildcard such as * or invoice.* is not a valid name: it answers 422 and nothing is created. To react to a whole family, list its events (the catalog groups them by category):

{ "enabled_events": ["invoice.created", "invoice.sent", "invoice.paid"] }

An account webhook endpoint takes these same names and also the account.* events, mixed in the same list.

List events via API

GET /v1/companies/{company}/events?type=invoice.paid&limit=50

Available filters: type, type[in], created[gte], created[lte], created[gt], created[lt]. Standard cursor pagination (limit, starting_after, ending_before) — see Pagination.

Events are kept for 30 days: older ones no longer appear in the list. The deliveries of a webhook keep their own copy of the payload for 90 days.

The event log belongs to the account that owns the tax ID. On a tax ID that your account reaches through a relation with another account — one that was granted to you, or one that belongs to an account you manage — GET /v1/companies/{company}/events and GET /v1/companies/{company}/events/{id} answer 403 forbidden_action, and so do the MCP tools list_events and get_event. On your own tax IDs they work as described. To follow the events of the accounts you manage, use an account webhook endpoint.

Order events

Subscribe to order.invoiced and order.refunded to receive full invoice or corrective-invoice snapshots under data.object. Both include data.store.uuid, data.store.provider and data.order.external_id; refunds also include data.refund.scope and data.refund.reason_code. Use the event id for delivery deduplication and correlation_id for related operations. See store processing and the n8n trigger.

if (event.type === "order.invoiced" || event.type === "order.refunded") {
  const invoice = event.data.object;
  const storeId = event.data.store.uuid;
  const orderId = event.data.order.external_id;
  await saveOrderDocument({ eventId: event.id, storeId, orderId, invoice });
}

On this page

Need a hand?Contact support