Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/integrations/integration-toolkit/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -687,5 +687,10 @@ token for a middleware:
| `POST /v1/integrations/{id}/events/replay` | `integration:manage` |
| `POST /v1/integrations/{id}/outbound/messages/poll`, `…/ack` | `integration:consume` |

The monitoring events list (`POST /v2/integrations/{id}/monitoring/events`) returns
`403` without `integration:view` on that integration. Its event details can carry customer
data — a mapped [poll message](./pollable-outbound.md#what-a-mapped-message-looks-like-in-monitoring)
includes its delivered payload.

Inbound event submission authenticates as the integration's own API token rather
than through these actions — see [Inbound Getting Started](./inbound/getting-started.md).
2 changes: 1 addition & 1 deletion docs/integrations/integration-toolkit/monitoring/codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Lifecycle markers rather than outcomes: a message was queued, a duplicate was ig
| `EXTERNAL_INFO` | An informational span pushed by an external system via the external monitoring events endpoint. |
| `FAN_OUT_EMPTY` | The split expression returned an empty list, so nothing was sent — expected for events that carry no relevant items |
| `FILE_PROXY_UPLOAD_ENQUEUED` | A per-file upload was accepted for delivery during fan-out |
| `MSG_ENQUEUED` | Outbound message enqueued to the poll queue, awaiting consumption by the ERP |
| `MSG_ENQUEUED` | Outbound message enqueued to the poll queue, awaiting consumption by the ERP. When the use case maps the payload, the detail carries the mapped payload as delivered and its mapping_version (or payload_omitted when it exceeds 48 KiB) |
## Status-code families

Some codes are generated from an upstream response rather than drawn from the fixed list above.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ Things worth knowing before you use it:
Everything the Monitoring tab shows is available directly. All three endpoints take a
POST body and are scoped to one integration.

Reading the event stream requires the `integration:view` grant on that integration — a
wildcard grant or one scoped to the integration; a grant scoped to a different
integration is not enough. Without it the request returns `403`. Event details can carry
customer data, such as the delivered payload of a mapped
[poll message](../pollable-outbound.md#what-a-mapped-message-looks-like-in-monitoring).

**The event stream** — filter by `level`, `code`, `use_case_id`, `use_case_type`,
`event_id`, `correlation_id` and a time range, with cursor pagination:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Each row in the stream is one monitoring event:
| `level` | How much you should care: `success`, `error`, `warning` or `info` |
| `code` | What specifically happened — see the [code reference](./codes.md) |
| `message` | A human-readable line, usually the error text |
| `detail` | Free-form JSON with context for that code — including the captured request and response where there was one |
| `detail` | Free-form JSON with context for that code — including the captured request and response where there was one, and for a mapped [poll message](../pollable-outbound.md#what-a-mapped-message-looks-like-in-monitoring) the payload as delivered |
| `use_case_type` | Which lane produced it |
| `use_case_id` | Which configured use case, when one owns the event |
| `event_id` | The triggering event |
Expand Down
34 changes: 33 additions & 1 deletion docs/integrations/integration-toolkit/pollable-outbound.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ Poll-queue message lifecycle events flow through the standard monitoring pipelin

| Code | Level | Emitted when |
|------|-------|--------------|
| `MSG_ENQUEUED` | info | A new queue item is enqueued for a poll-mode use case (duplicates emit nothing) |
| `MSG_ENQUEUED` | info | A new queue item is enqueued for a poll-mode use case (duplicates emit nothing). For a mapped message the detail also carries the delivered payload — see [What a mapped message looks like in monitoring](#what-a-mapped-message-looks-like-in-monitoring) |
| `MSG_ACKED` | success | A polled message is acknowledged (one event per accepted message id) |
| `MSG_EXPIRED_UNPOLLED` | error | An item's retention window elapsed without it ever being consumed — the offline-consumer loss signal |
| `MSG_DEAD_LETTERED` | error | A message exhausted `max_delivery_attempts` under the `dead_letter` policy, or an operator skipped a blocked head (includes `delivery_attempts` in the event detail) |
Expand All @@ -589,6 +589,38 @@ When a failed mapping reaches the head, `MSG_DEAD_LETTERED` or `MSG_HEAD_BLOCKED

Lease lapses (a message reappearing after a visibility timeout) are deliberately **not** a per-occurrence signal — they are normal at-least-once behavior and would be noisy. The attempt count is reported on `MSG_DEAD_LETTERED` / `MSG_HEAD_BLOCKED`, which are the actionable events.

### What a mapped message looks like in monitoring

When a [payload mapping](#payload-mapping) transforms a message, its `MSG_ENQUEUED` event shows what the consumer will receive, so you can inspect a transform's result next to its trigger event in the monitoring trace. The `payload` is exactly what the poll API delivers:

```json
{
"message_id": "msg_9f3c8a1b…",
"event_name": "MeterReadingAdded",
"mapping_version": "3f9a1c0b7d2e4a65",
"payload": { "meter_number": "A-1002", "reason": "PERIODIC" }
}
```

Monitoring keeps a payload of up to **48 KiB** (serialized JSON). A larger one is left out and described instead, still with its `mapping_version`:

```json
{
"message_id": "msg_9f3c8a1b…",
"event_name": "MeterReadingAdded",
"mapping_version": "3f9a1c0b7d2e4a65",
"payload_omitted": { "reason": "too_large", "size_bytes": 81234, "limit_bytes": 49152 }
}
```

The limit exists because a page of monitoring events returns up to 100 events with their details inline, and every page has to fit in one API response. `limit_bytes` carries the limit, so you never need to hard-code it.

Raw and failed messages keep the plain detail, `{ "message_id": "…", "event_name": "…" }`. A raw message's payload is the trigger event, which the trace already shows, so monitoring stores no second copy. A failed message has its own [`MAPPING_EXPRESSION_FAILED`](#mapping-failures) event.

:::caution Mapped payloads are copied into monitoring
A transformed payload usually contains customer data, and this copy is kept as long as the integration's other monitoring events. Anyone who can read the integration's monitoring events can see it. The monitoring events list and the trace both require the `integration:view` grant on the integration.
:::

### Queue health in `outbound-status`

For poll-mode use cases, `GET /v1/integrations/{integrationId}/outbound-status` reports a `poll` health object per use case (webhook-only use cases keep their existing status shape unchanged):
Expand Down
Loading