# Document Events _(Realtime-enabled)_

`GET` _(Table: EONE Document Event)_

```
eOne/core/v1.0/documentEvents
```

A read-only feed of **named document-lifecycle events** built for webhook subscriptions. One row per transition, and the row says what happened - `salesDocumentReleased`, `stagedDocumentPosted`, `postedSalesDocumentClosed` - so SmartConnect triggers on the event itself instead of re-reading documents and comparing statuses.

## Why it exists

A standard webhook subscription on a document endpoint tells SmartConnect that a record changed, not what the change was. Working out that an order was released means fetching it again and comparing the status you stored last time, and a cancelled document is just a delete notification. This feed removes that work: every meaningful transition writes one event row, the row names the transition, and the webhook notification points straight at it.

The event is written in the same database transaction as the change it announces. A posting that fails or rolls back leaves no event behind, and a posting that commits always has one.

```mermaid
flowchart LR
    A[Document transition] --> B{Transaction commits?}
    B -->|No| C[No event: the row rolls back with the change]
    B -->|Yes| D[Event row written, next sequence number]
    D --> E[Change tracking fires the webhook]
    E --> F[Subscriber stores the highest sequence it processed]
    F -->|after an outage| G[Replay with sequence gt last seen]
    G --> F
    D --> H[Purged after the retention window of 7, 14 or 28 days]
```

## What one event tells you

Each row identifies three documents, so a map rarely needs a follow-up lookup:

- **The subject** - `documentType`, `documentNumber`, `documentId`, and its `integrationId`.
- **Where it came from** - `sourceDocumentNumber` and `sourceIntegrationId`, the order behind a shipment or invoice. `sourceIntegrationId` is the key SmartConnect already holds, so a `salesInvoicePosted` event maps back to the originating order with no lookup step.
- **What it produced** - `resultDocumentNumber`, such as the posted G/L document behind a `stagedDocumentPosted` event or the corrective credit memo behind a cancellation.

`webClientUrl` links a person straight to the document in Business Central, which is useful when an event feeds an alert or a task rather than a map.

## The event catalog

The full list is published in `$metadata` as the member list of `eventType`. In lifecycle order:

| Stage | Events |
| --- | --- |
| Open documents | `salesDocumentReleased` / `Reopened` / `Archived` / `Cancelled` / `Deleted`, the five `purchaseDocument…` twins, `transferOrderReleased` / `Reopened` / `transferOrderDeleted` |
| Staged documents | `stagedDocumentPendingApproval`, `Approved`, `AwaitingInvoice`, `AwaitingLines`, `Errored` (with the error text in `detail`), `Drafted`, `Posted` |
| Warehouse fulfillment | `warehouseShipmentCreated` / `Released` / `Reopened` / `Deleted`, `warehouseReceiptCreated` / `Deleted` |
| Posting | `salesShipmentPosted`, `salesInvoicePosted`, `salesCreditMemoPosted`, `salesReturnReceiptPosted`, the four purchase twins, `transferShipmentPosted`, `transferReceiptPosted` |
| Posted documents | `postedSalesDocumentClosed` / `Reopened`, `postedPurchaseDocumentClosed` / `Reopened`, `postedSalesInvoiceCancelled`, `postedPurchaseInvoiceCancelled` |

`Closed` fires when the posted document's ledger entry is fully applied, whichever way the application happened - a payment posted with an apply-to, a manual application in the client, or a payment journal. `Reopened` fires when an unapplication opens it again.

`Deleted` fires when somebody removes an open document in the client without archiving it. It is the only event in the catalog that records something Business Central keeps no other record of: an archived or cancelled document leaves a snapshot behind, a posted one becomes a posted document, but a plain deletion leaves nothing. A store that mirrors open documents needs this event, because the document simply stops being returned by its feed and no amount of re-reading will explain why.

Posting and cancelling delete a sales, purchase or transfer document too, and each already has its own event, so neither raises a second `Deleted` for the same record.

`Deleted` carries the deleted record's `documentId`, so a store that keys on it can match the row exactly rather than searching by document number. `webClientUrl` is blank, because that link would open nothing. `Cancelled` differs here: it leaves `documentId` blank, so matching a cancellation means `documentNumber` plus `documentType`. A cancelled document's content is not lost - the cancel action snapshots it first, and `archivedSalesDocumentsQuery` / `archivedPurchaseDocumentsQuery` return those snapshots with `Cancelled` set to true.

`warehouseShipmentDeleted` and `warehouseReceiptDeleted` work differently, because a warehouse document has no posted event of its own. Posting it posts the orders behind it, and those raise their own `salesShipmentPosted` or `purchaseReceiptPosted` events. Business Central then deletes the warehouse document once every line is fully handled. So the warehouse `Deleted` event fires on both endings, posted or abandoned, and it is the only signal that the document has left. A partial posting leaves the document in place, so no event fires until the last line is handled.

To tell the two endings apart, check the order behind the document. When the warehouse document was posted, the order's posted event is written in the same transaction. The warehouse `Deleted` event carries `documentId` and `integrationId`. Its `sourceDocumentNumber`, `sourceIntegrationId` and `webClientUrl` are blank, because the document and its lines are already gone when the event is written.

## Subscribing and filtering

Subscribe to this entity set the same way as any other webhook target; see [Real-time notifications](https://eonesolutions.github.io/eone-bc-integration/realtime.md). A webhook subscription itself cannot carry a filter, so subscribe once and filter on the read: the notification hands you the changed rows, and `$filter=eventType eq 'salesDocumentReleased'` narrows a catch-up read to the transitions a map cares about. Every column is filterable.

## Catching up after an outage

`sequence` is a monotonic event number. Store the last value you processed, and after any gap read `$filter=sequence gt {last seen}` to replay everything missed, in order. Event rows are purged after the retention window set on the eOne Integration Setup page (7, 14 or 28 days), so the window is also the longest outage a subscriber can bridge; the purge shows up as delete notifications on the subscription, which a cursor-based reader simply ignores.

## Off by default: enable it in Setup

Nothing is recorded until an administrator turns on **Document Events** on the eOne Integration Setup page, and while it is off this feed returns an error rather than a silent, frozen stream. The posted-document status events (`postedSalesDocumentClosed` and its siblings) have a second switch, **Posted Document Status Events**, because recording them means watching every customer and vendor ledger entry application; leave it off unless SmartConnect acts on settlement.

## Document Events fields

_API column → BC field._

**Legend**

- _(req)_ required on create
- _(res)_ resolver
- _(cur)_ currency-translated
- _(ro)_ read-only
- _(ext)_ added to this endpoint by another extension (BC field name shown; its API column name is not known here)

| API | BC field | Notes |
| --- | --- | --- |
| `id` | SystemId | BC record GUID of the event row (what webhook notifications address). _(ro)_ |
| `bcCompanyId` | bcCompanyId | The company this row belongs to - the same GUID that appears in the request URL. Present on every endpoint so a store pooling several companies can keep them apart without relying on which URL it called. _(ro)_ |
| `bcCompanyName` | bcCompanyName | The name of the company this row belongs to. _(ro)_ |
| `sequence` | Sequence | Monotonic event number - the catch-up cursor. After an outage, filter sequence gt {last seen} to replay everything missed. _(ro)_ |
| `eventType` | Event Type | The named transition, e.g. salesDocumentReleased or stagedDocumentPosted. The full catalog is published in $metadata as this field's member list. _(ro)_ |
| `occurredAt` | Occurred At | When the transition happened. _(ro)_ |
| `initiatedBy` | Initiated By | The Business Central user or service account whose session raised the event. _(ro)_ |
| `documentType` | Document Type | The subject document's type within its family - Order, Invoice, Credit Memo, or a staged document type. _(ro)_ |
| `documentNumber` | Document No. | The subject document's number. _(ro)_ |
| `documentId` | Document Id | SystemId of the subject document - the direct GET handle on its own endpoint. Empty on cancelled events (the document is deleted; the archive keeps the snapshot). _(ro)_ |
| `integrationId` | Integration Id | The subject document's Integration Id (your external key). _(ro)_ |
| `sourceDocumentNumber` | Source Document No. | The upstream document that produced the subject: the order behind a shipment or invoice, the pre-assigned number behind a directly posted invoice, the source order behind a warehouse shipment. Empty where there is none. _(ro)_ |
| `sourceIntegrationId` | Source Integration Id | The upstream document's Integration Id - the key your system already holds, so posted artifacts map back to their order without a lookup. _(ro)_ |
| `resultDocumentNumber` | Result Document No. | The downstream artifact where the transition produced one: the posted G/L document on stagedDocumentPosted, the draft journal document on stagedDocumentDrafted, the corrective credit memo on postedSalesInvoiceCancelled. Empty otherwise. _(ro)_ |
| `detail` | Detail | Short context text - the error message on stagedDocumentErrored, otherwise empty. _(ro)_ |
| `webClientUrl` | Web Client URL | Deep link to the subject document in the Business Central web client, for human-facing consumers. _(ro)_ |
| `lastModifiedDateTime` | SystemModifiedAt | _(ro)_ |
