{"openapi":"3.1.0","info":{"title":"Webhooks API","version":"0.1.0","description":"How an app learns what happened in a tenant (`docs/sales-channels.md` §2.4). An app subscribes to topics from a public, versioned catalogue (`WebhookTopic`); the service reads the core journals, turns each fact into the event it stands for and delivers it to every subscription of an installation granted the topic's scope — signed per installation, retried with backoff for about a day, logged, and redeliverable."},"paths":{"/subscriptions":{"get":{"tags":["subscriptions"],"operationId":"subscriptions.list","parameters":[],"security":[{"bearer":[]}],"responses":{"200":{"description":"WebhookSubscriptionList","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionListEncoded"},"examples":{"contract":{"summary":"subscriptions.list","value":{"items":[{"id":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0","tenantId":"org_01a15889-fa80-7d83-add6-41f282c51558","appId":"app_01a158db-8198-7d68-bdb3-a6b194c0ce9e","installationId":"ins_01a158dd-98c0-7c1e-9f42-3b7d2a1e6c05","url":"https://hooks.tidewater-labels.example/manifold","topics":["order.created","shipment.shipped"],"createdAt":"2026-10-20T11:00:00.000Z","updatedAt":"2026-10-20T11:00:00.000Z"}]}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"AppTokenRequired | TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppTokenRequiredEncoded"},{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"The calling app's webhook subscriptions in this tenant: each with its URL and topics. What a subscription receives is still bounded by the installation's grant when each event is delivered.\n\nRequires a signed-in session: an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant","x-mcp-withheld":"An app's webhook plumbing — its subscriptions, delivery log and signing secret — answers that app's own token alone; an agent acts as a person and reads what happened through the journals' tools instead.","x-requires":{"kind":"signed-in","reason":"an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant"},"x-example-source":{"origin":"contract"}}},"/subscriptions/{subscriptionId}":{"put":{"tags":["subscriptions"],"operationId":"subscriptions.save","parameters":[{"name":"subscriptionId","in":"path","schema":{"$ref":"#/components/schemas/WhsId"},"required":true,"example":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"WebhookSubscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionEncoded"},"examples":{"contract":{"summary":"subscriptions.save","value":{"id":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0","tenantId":"org_01a15889-fa80-7d83-add6-41f282c51558","appId":"app_01a158db-8198-7d68-bdb3-a6b194c0ce9e","installationId":"ins_01a158dd-98c0-7c1e-9f42-3b7d2a1e6c05","url":"https://hooks.tidewater-labels.example/manifold","topics":["order.created","shipment.shipped"],"createdAt":"2026-10-20T11:00:00.000Z","updatedAt":"2026-10-20T11:00:00.000Z"}}}}}},"400":{"description":"UnsafeWebhookUrl","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnsafeWebhookUrlEncoded"}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"AppTokenRequired | TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppTokenRequiredEncoded"},{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"404":{"description":"WebhookSubscriptionNotFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionNotFoundEncoded"}}}},"409":{"description":"TopicNotGranted | MirroredFromSource","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TopicNotGrantedEncoded"},{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}]}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Subscribe the calling app to topics at a URL, or change a subscription: the app mints `subscriptionId` (`whs_…`) and sends the whole of it. Events from the moment of saving on are delivered — none from before. Appends `webhooks.subscription-saved`. 409 `TopicNotGranted` for a topic whose scope the installation was not granted; 400 `UnsafeWebhookUrl` for a URL that is not https or names a private address (a first-party app may name the platform's own hosts); 404 `WebhookSubscriptionNotFound` for an id another app holds. Idempotent by content: a retry that changes nothing is acknowledged and appends nothing.\n\nRequires a signed-in session: an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveWebhookSubscriptionEncoded"},"example":{"url":"https://hooks.tidewater-labels.example/manifold","topics":["order.created","shipment.shipped"]}}},"required":true},"x-mcp-withheld":"An app's webhook plumbing — its subscriptions, delivery log and signing secret — answers that app's own token alone; an agent acts as a person and reads what happened through the journals' tools instead.","x-requires":{"kind":"signed-in","reason":"an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant"},"x-example-source":{"origin":"contract"}},"delete":{"tags":["subscriptions"],"operationId":"subscriptions.delete","parameters":[{"name":"subscriptionId","in":"path","schema":{"$ref":"#/components/schemas/WhsId"},"required":true,"example":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"WebhookSubscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionEncoded"},"examples":{"contract":{"summary":"subscriptions.delete","value":{"id":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0","tenantId":"org_01a15889-fa80-7d83-add6-41f282c51558","appId":"app_01a158db-8198-7d68-bdb3-a6b194c0ce9e","installationId":"ins_01a158dd-98c0-7c1e-9f42-3b7d2a1e6c05","url":"https://hooks.tidewater-labels.example/manifold","topics":["order.created","shipment.shipped"],"createdAt":"2026-10-20T11:00:00.000Z","updatedAt":"2026-10-21T08:15:00.000Z"}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"AppTokenRequired | TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppTokenRequiredEncoded"},{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"404":{"description":"WebhookSubscriptionNotFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscriptionNotFoundEncoded"}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Let a subscription go: nothing more is delivered to it, and its pending deliveries are dropped. Appends `webhooks.subscription-deleted`. Idempotent by state: deleting it again is acknowledged and appends nothing (404 `WebhookSubscriptionNotFound` for one the app never had).\n\nRequires a signed-in session: an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant","x-mcp-withheld":"An app's webhook plumbing — its subscriptions, delivery log and signing secret — answers that app's own token alone; an agent acts as a person and reads what happened through the journals' tools instead.","x-requires":{"kind":"signed-in","reason":"an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant"},"x-example-source":{"origin":"contract"}}},"/signing-secret":{"get":{"tags":["subscriptions"],"operationId":"subscriptions.signingSecret","parameters":[],"security":[{"bearer":[]}],"responses":{"200":{"description":"WebhookSigningSecret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSigningSecretEncoded"},"examples":{"contract":{"summary":"subscriptions.signingSecret","value":{"secret":"5e0b8c4a2f7d19e63b1a0c9f8e7d6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f"}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"AppTokenRequired | TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppTokenRequiredEncoded"},{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"The secret the calling app's deliveries are signed with in this tenant: `Manifold-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">`. Verify it over the raw body and refuse one more than five minutes old.\n\nRequires a signed-in session: an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant","x-mcp-withheld":"An app's webhook plumbing — its subscriptions, delivery log and signing secret — answers that app's own token alone; an agent acts as a person and reads what happened through the journals' tools instead.","x-requires":{"kind":"signed-in","reason":"an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant"},"x-example-source":{"origin":"contract"}}},"/deliveries":{"get":{"tags":["deliveries"],"operationId":"deliveries.list","parameters":[{"name":"subscriptionId","in":"query","schema":{"$ref":"#/components/schemas/WhsId"},"required":false,"example":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0"},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/WebhookDeliveryStatus"},"required":false},{"name":"before","in":"query","schema":{"$ref":"#/components/schemas/WhdId"},"required":false},{"name":"limit","in":"query","schema":{"type":"string"},"required":false,"example":"2"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"WebhookDeliveryPage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryPageEncoded"},"examples":{"contract":{"summary":"deliveries.list","value":{"items":[{"id":"whd_01a158e3-de38-7b52-a1f7-8c4e2d9b0a13","subscriptionId":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0","eventId":"whe_01a158e3-1b20-7c44-9e0a-5f3d8c2b7e91","topic":"shipment.shipped","status":"delivered","attempts":1,"lastStatus":200,"createdAt":"2026-10-20T11:42:10.000Z","deliveredAt":"2026-10-20T11:42:11.000Z"},{"id":"whd_01a158e1-c710-7a3b-8d55-1e9f0c7b2a64","subscriptionId":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0","eventId":"whe_01a158e0-af10-7f21-b3c8-6d2e4a9f1b70","topic":"order.created","status":"failed","attempts":9,"lastStatus":503,"lastError":"answered 503","createdAt":"2026-10-19T11:20:04.000Z"}],"next":"whd_01a158e1-c710-7a3b-8d55-1e9f0c7b2a64"}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"AppTokenRequired | TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppTokenRequiredEncoded"},{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"The calling app's delivery log, newest first: each event's delivery to one of its subscriptions, its attempts, the app's last answer and when it is tried next. Narrow to a `subscriptionId` or a `status`; page with `before`.\n\nRequires a signed-in session: an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant","x-mcp-withheld":"An app's webhook plumbing — its subscriptions, delivery log and signing secret — answers that app's own token alone; an agent acts as a person and reads what happened through the journals' tools instead.","x-requires":{"kind":"signed-in","reason":"an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant"},"x-example-source":{"origin":"contract"}}},"/deliveries/{deliveryId}":{"get":{"tags":["deliveries"],"operationId":"deliveries.get","parameters":[{"name":"deliveryId","in":"path","schema":{"$ref":"#/components/schemas/WhdId"},"required":true,"example":"whd_01a158e1-c710-7a3b-8d55-1e9f0c7b2a64"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"WebhookDelivery","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryEncoded"},"examples":{"contract":{"summary":"deliveries.get","value":{"id":"whd_01a158e1-c710-7a3b-8d55-1e9f0c7b2a64","subscriptionId":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0","eventId":"whe_01a158e0-af10-7f21-b3c8-6d2e4a9f1b70","topic":"order.created","status":"failed","attempts":9,"lastStatus":503,"lastError":"answered 503","createdAt":"2026-10-19T11:20:04.000Z"}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"AppTokenRequired | TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppTokenRequiredEncoded"},{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"404":{"description":"WebhookDeliveryNotFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryNotFoundEncoded"}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"One of the calling app's deliveries, with its attempts and the app's last answer. 404 `WebhookDeliveryNotFound`.\n\nRequires a signed-in session: an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant","x-mcp-withheld":"An app's webhook plumbing — its subscriptions, delivery log and signing secret — answers that app's own token alone; an agent acts as a person and reads what happened through the journals' tools instead.","x-requires":{"kind":"signed-in","reason":"an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant"},"x-example-source":{"origin":"contract"}}},"/deliveries/{deliveryId}/redeliver":{"post":{"tags":["deliveries"],"operationId":"deliveries.redeliver","parameters":[{"name":"deliveryId","in":"path","schema":{"$ref":"#/components/schemas/WhdId"},"required":true,"example":"whd_01a158e1-c710-7a3b-8d55-1e9f0c7b2a64"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"WebhookDelivery","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryEncoded"},"examples":{"contract":{"summary":"A failed delivery queued again: it is tried at once, its earlier attempts kept.","value":{"id":"whd_01a158e1-c710-7a3b-8d55-1e9f0c7b2a64","subscriptionId":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0","eventId":"whe_01a158e0-af10-7f21-b3c8-6d2e4a9f1b70","topic":"order.created","status":"pending","attempts":9,"lastStatus":503,"lastError":"answered 503","createdAt":"2026-10-19T11:20:04.000Z","nextAttemptAt":"2026-10-20T12:05:00.000Z"}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"AppTokenRequired | TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AppTokenRequiredEncoded"},{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"404":{"description":"WebhookDeliveryNotFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryNotFoundEncoded"}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Send one of the calling app's deliveries again, now — a failed one once the app is fixed, or a delivered one it lost. The same event id, so the app recognises it. Appends nothing: a delivery is the dispatcher's execution state, not a fact of the tenant's. No idempotency key: redelivering is meant to send again, and a second call only queues the same event once more.\n\nRequires a signed-in session: an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant","x-mcp-withheld":"An app's webhook plumbing — its subscriptions, delivery log and signing secret — answers that app's own token alone; an agent acts as a person and reads what happened through the journals' tools instead.","x-requires":{"kind":"signed-in","reason":"an app token: subscriptions and their deliveries belong to the calling app alone, and each topic is held to its own grant"},"x-example-source":{"origin":"contract"}}},"/events":{"get":{"tags":["events"],"operationId":"events.list","parameters":[{"name":"since","in":"query","schema":{"type":"string"},"required":false,"example":"0"},{"name":"limit","in":"query","schema":{"type":"string"},"required":false,"example":"500"},{"name":"upTo","in":"query","schema":{"type":"string"},"required":false}],"security":[{"bearer":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/webhooks.subscription-savedEncoded"},{"$ref":"#/components/schemas/webhooks.subscription-deletedEncoded"}]}},"examples":{"contract":{"summary":"events.list","value":[{"_tag":"webhooks.subscription-saved","eventId":"evt_01a158e5-f560-7d19-8b2c-4a7e1f0d3c58","txId":"tx_01a158e5-f560-7e0a-a3d4-9b1c6e2f8a07","tenantId":"org_01a15889-fa80-7d83-add6-41f282c51558","sequence":0,"occurredAt":"2026-10-20T11:00:00.000Z","source":"webhooks","version":1,"actor":{"_tag":"app","id":"app_01a158db-8198-7d68-bdb3-a6b194c0ce9e","installationId":"ins_01a158dd-98c0-7c1e-9f42-3b7d2a1e6c05"},"correlationId":"req_01a158e5-f560-7f3b-9c11-2d8e5a4b6f90","payload":{"subscriptionId":"whs_01a158d9-6a70-7aa9-a2e3-50b645a781d0","appId":"app_01a158db-8198-7d68-bdb3-a6b194c0ce9e","installationId":"ins_01a158dd-98c0-7c1e-9f42-3b7d2a1e6c05","url":"https://hooks.tidewater-labels.example/manifold","topics":["order.created","shipment.shipped"]}}]}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"Replay committed webhooks events at-or-after `since` (a journal sequence number), oldest first: every subscription an app saved or let go. One response is a page: `limit` defaults to 500 and is capped at 5000 (an over-cap request is clamped). Pages are `sequence`-ordered and the boundary is stable — repeat with `since=<last event's sequence + 1>` until a page comes back smaller than `limit` to replay the journal exactly once. `upTo` (inclusive) ends the replay at a sequence instead of the journal's head — with `GET /events/head` it replays the journal as it stood at a moment. Appends nothing: a read of facts already journalled.\n\nRequires `integrations:read`.","x-mcp-withheld":"The journal replay a consumer pages through to build its projection; agents read the projections the list and get tools serve, and the audit trail (`audit_trail`) for history.","x-required-scopes":["integrations:read"],"x-example-source":{"origin":"contract"}}},"/events/head":{"get":{"tags":["events"],"operationId":"events.head","parameters":[{"name":"at","in":"query","schema":{"type":"string"},"required":true,"example":"2026-10-20T11:00:05.000Z"}],"security":[{"bearer":[]}],"responses":{"200":{"description":"Where a tenant's journal stood at a moment.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JournalHead"},"examples":{"contract":{"summary":"events.head","value":{"at":"2026-10-20T11:00:05.000Z","sequence":0}}}}}},"401":{"description":"Unauthorized | TokenAlreadyUsed","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnauthorizedEncoded"},{"$ref":"#/components/schemas/TokenAlreadyUsedEncoded"}]}}}},"402":{"description":"SubscriptionRequired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionRequiredEncoded"}}}},"403":{"description":"TenantRequired | ScopeRequired | PlatformAdminRequired","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/TenantRequiredEncoded"},{"$ref":"#/components/schemas/ScopeRequiredEncoded"},{"$ref":"#/components/schemas/PlatformAdminRequiredEncoded"}]}}}},"409":{"description":"MirroredFromSource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MirroredFromSourceEncoded"}}}},"503":{"description":"RequestLogUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestLogUnavailableEncoded"}}}}},"description":"The journal's position at a moment: the last `sequence` the database had recorded for this tenant at `at` (absent when it held nothing yet), by the database's own clock rather than the service's. Replaying with `upTo=<sequence>` then gives the journal exactly as it stood then; a set of heads taken at one `at` is a consistent cut across journals. Appends nothing: a read of facts already journalled.\n\nRequires `integrations:read`.","x-mcp-withheld":"Where a journal stood at a moment, for a consumer cutting journals to replay them as of then; agents read history through the audit trail (`audit_trail`).","x-required-scopes":["integrations:read"],"x-example-source":{"origin":"contract"}}}},"components":{"schemas":{"WhsId":{"type":"string","pattern":"^whs_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A whs-prefixed uuid, e.g. whs_9f8c1c2e-0000-4000-8000-000000000000"},"TenantId":{"type":"string","pattern":"^org_(test_)?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"An org-prefixed uuid, e.g. org_9f8c1c2e-0000-4000-8000-000000000000; a sandbox tenant is org_test_<uuid>"},"AppId":{"type":"string","pattern":"^app_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A app-prefixed uuid, e.g. app_9f8c1c2e-0000-4000-8000-000000000000"},"InsId":{"type":"string","pattern":"^ins_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A ins-prefixed uuid, e.g. ins_9f8c1c2e-0000-4000-8000-000000000000"},"WebhookTopic":{"type":"string","enum":["order.created","order.edited","order.cancelled","shipment.shipped","allocation.moved","payment.recorded","refund.created","stock.changed","location.updated","channel.disconnected","app.uninstalled","chart.sync-requested","organization.mode-changed","billing.usage-recorded","consignment.requested","consignment.voided","manifest.requested","item.updated","payment.collection-requested","invoice.issued"],"description":"`order.created` — an order was placed (a quote is not an order until placed); `order.edited` — an order's lines, charges or discounts changed after placing; `order.cancelled` — an order was cancelled; `shipment.shipped` — a parcel left a site, with its carrier and tracking when known; `allocation.moved` — a person moved a line's allocation to another site; `payment.recorded` — money was received against an order; `refund.created` — money (and perhaps stock) went back to a customer; `stock.changed` — what may be sold of some SKUs moved at some sites (read the levels through the API); `location.updated` — a site was renamed, re-addressed, switched in or out of fulfilment, or archived; `channel.disconnected` — one of the tenant's sales channels was let go; `chart.sync-requested` — a person asked the ledger apps that keep the chart of accounts to sync it now (`data.appIds` names them; an app not named ignores it); `organization.mode-changed` — an owner or admin took the organization live (final), or pinned an undecided one read-only (`data.mode` is where that decision left it; an app that remembers the mode asks `GET /api/auth/mode` again); `billing.usage-recorded` — a sales order of a tenant billed through this app was counted on the metered price: report it as one unit of usage to the app's billing provider, under `data.key` as the idempotency key (sent only to the app the tenant is billed through, `data.appId`); `consignment.requested` — a parcel was put to a carrier account this app keeps, to book (sent only to `data.appId`; answer it through the carrier-account API); `consignment.voided` — a consignment this app booked (or was asked to) was cancelled: cancel it at the carrier (sent only to `data.appId`); `manifest.requested` — a person handed over a carrier account's booked parcels: lodge the manifest with the carrier and answer it (sent only to `data.appId`); `item.updated` — a SKU was created, or its name, weight, packed size, own-packaging flag, order rules, barcodes, tariff codes or country of origin changed (read the item through the API); `payment.collection-requested` — a person (or this app) asked the order's sales channel to collect its money through the channel's own payment system — capture an authorisation or charge a saved method: do it and answer through `POST /orders/:orderId/collections/:collectionId/answer` (sent only to the app providing the channel, `data.appId`); `invoice.issued` — an order was invoiced: what it bills and, on payment terms, when it falls due; `app.uninstalled` — the tenant removed this app (sent to the app itself, whatever it subscribed to)"},"WebhookSubscriptionEncoded":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/WhsId"},"tenantId":{"$ref":"#/components/schemas/TenantId"},"appId":{"$ref":"#/components/schemas/AppId"},"installationId":{"$ref":"#/components/schemas/InsId"},"url":{"type":"string"},"topics":{"type":"array","items":{"$ref":"#/components/schemas/WebhookTopic"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","tenantId","appId","installationId","url","topics","createdAt","updatedAt"],"additionalProperties":false},"WebhookSubscriptionListEncoded":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/WebhookSubscriptionEncoded"}}},"required":["items"],"additionalProperties":false},"AppTokenRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["AppTokenRequired"]},"reason":{"type":"string"}},"required":["_tag","reason"],"additionalProperties":false},"TenantRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["TenantRequired"]},"userId":{"type":"string"}},"required":["_tag","userId"],"additionalProperties":false},"ScopeRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["ScopeRequired"]},"required":{"type":"array","items":{"type":"string"}}},"required":["_tag","required"],"additionalProperties":false},"PlatformAdminRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["PlatformAdminRequired"]},"userId":{"type":"string"}},"required":["_tag","userId"],"additionalProperties":false},"UnauthorizedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["Unauthorized"]},"reason":{"type":"string"}},"required":["_tag","reason"],"additionalProperties":false},"TokenAlreadyUsedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["TokenAlreadyUsed"]},"tokenId":{"type":"string"}},"required":["_tag","tokenId"],"additionalProperties":false},"RequestLogUnavailableEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["RequestLogUnavailable"]},"tokenId":{"type":"string"},"reason":{"type":"string"}},"required":["_tag","tokenId","reason"],"additionalProperties":false},"SubscriptionRequiredEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["SubscriptionRequired"]},"status":{"type":"string"}},"required":["_tag","status"],"additionalProperties":false},"MirroredFromSourceEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["MirroredFromSource"]},"source":{"type":"string"}},"required":["_tag","source"],"additionalProperties":false},"SaveWebhookSubscriptionEncoded":{"type":"object","properties":{"url":{"type":"string","minLength":1,"maxLength":2000},"topics":{"type":"array","items":{"$ref":"#/components/schemas/WebhookTopic"},"minItems":1}},"required":["url","topics"],"additionalProperties":false},"Scope":{"type":"string","enum":["products:read","products:write","catalogs:read","catalogs:write","stock:read","stock:write","receiving:read","receiving:write","allocations:read","allocations:write","locations:read","locations:write","orders:read","orders:write","shipping:read","shipping:write","payments:read","payments:write","purchasing:read","purchasing:write","customers:read","customers:write","companies:read","companies:write","privacy:read","privacy:write","financials:read","financials:write","books:read","books:write","margins:read","margins:write","reports:read","reports:write","imports:read","imports:write","integrations:read","integrations:write","setup:read","setup:write","billing:read","billing:write","activity:read","activity:write","settings:read","settings:write","notifications:read","notifications:write","saved-views:read","saved-views:write","commissions:read","commissions:write","catalog-override:read","catalog-override:write","printing:read","printing:write"],"description":"A permission an endpoint requires, `<resource>:<read|write>`; holding `write` implies `read`."},"TopicNotGrantedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["TopicNotGranted"]},"topic":{"$ref":"#/components/schemas/WebhookTopic"},"scope":{"$ref":"#/components/schemas/Scope"}},"required":["_tag","topic","scope"],"additionalProperties":false},"UnsafeWebhookUrlEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["UnsafeWebhookUrl"]},"url":{"type":"string"},"reason":{"type":"string"}},"required":["_tag","url","reason"],"additionalProperties":false},"WebhookSubscriptionNotFoundEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["WebhookSubscriptionNotFound"]},"subscriptionId":{"type":"string"}},"required":["_tag","subscriptionId"],"additionalProperties":false},"WebhookSigningSecretEncoded":{"type":"object","properties":{"secret":{"type":"string"}},"required":["secret"],"additionalProperties":false},"WebhookDeliveryStatus":{"type":"string","enum":["pending","delivered","failed"],"description":"`pending` — not yet accepted: waiting for its first attempt or its next retry; `delivered` — the app answered 2xx; `failed` — every retry was refused or unanswered (redeliver it once the app is fixed)"},"WhdId":{"type":"string","pattern":"^whd_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A whd-prefixed uuid, e.g. whd_9f8c1c2e-0000-4000-8000-000000000000"},"WheId":{"type":"string","pattern":"^whe_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A whe-prefixed uuid, e.g. whe_9f8c1c2e-0000-4000-8000-000000000000"},"WebhookDeliveryEncoded":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/WhdId"},"subscriptionId":{"$ref":"#/components/schemas/WhsId"},"eventId":{"$ref":"#/components/schemas/WheId"},"topic":{"$ref":"#/components/schemas/WebhookTopic"},"status":{"$ref":"#/components/schemas/WebhookDeliveryStatus"},"attempts":{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]},"lastStatus":{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]},"lastError":{"type":"string"},"createdAt":{"type":"string"},"nextAttemptAt":{"type":"string"},"deliveredAt":{"type":"string"}},"required":["id","subscriptionId","eventId","topic","status","attempts","createdAt"],"additionalProperties":false},"WebhookDeliveryPageEncoded":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDeliveryEncoded"}},"next":{"$ref":"#/components/schemas/WhdId"}},"required":["items"],"additionalProperties":false},"WebhookDeliveryNotFoundEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["WebhookDeliveryNotFound"]},"deliveryId":{"type":"string"}},"required":["_tag","deliveryId"],"additionalProperties":false},"EvtId":{"type":"string","pattern":"^evt_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A evt-prefixed uuid, e.g. evt_9f8c1c2e-0000-4000-8000-000000000000"},"TxId":{"type":"string","pattern":"^tx_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A tx-prefixed uuid, e.g. tx_9f8c1c2e-0000-4000-8000-000000000000"},"UsrId":{"type":"string","pattern":"^usr_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A usr-prefixed uuid, e.g. usr_9f8c1c2e-0000-4000-8000-000000000000"},"CplId":{"type":"string","pattern":"^cpl_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$","description":"A cpl-prefixed uuid, e.g. cpl_9f8c1c2e-0000-4000-8000-000000000000"},"Actor":{"anyOf":[{"type":"object","properties":{"_tag":{"type":"string","enum":["user"]},"id":{"$ref":"#/components/schemas/UsrId"},"impersonatedBy":{"type":"string","minLength":1},"viaPartner":{"type":"string","minLength":1}},"required":["_tag","id"],"additionalProperties":false},{"type":"object","properties":{"_tag":{"type":"string","enum":["system"]},"id":{"type":"string","minLength":1}},"required":["_tag","id"],"additionalProperties":false},{"type":"object","properties":{"_tag":{"type":"string","enum":["app"]},"id":{"$ref":"#/components/schemas/AppId"},"installationId":{"$ref":"#/components/schemas/InsId"}},"required":["_tag","id","installationId"],"additionalProperties":false},{"type":"object","properties":{"_tag":{"type":"string","enum":["customer"]},"id":{"$ref":"#/components/schemas/CplId"}},"required":["_tag","id"],"additionalProperties":false}]},"webhooks.subscription-savedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["webhooks.subscription-saved"]},"eventId":{"$ref":"#/components/schemas/EvtId"},"txId":{"$ref":"#/components/schemas/TxId"},"tenantId":{"$ref":"#/components/schemas/TenantId"},"sequence":{"type":"integer","minimum":0},"occurredAt":{"type":"string"},"source":{"type":"string","minLength":1},"version":{"type":"number","enum":[1]},"actor":{"$ref":"#/components/schemas/Actor"},"correlationId":{"type":"string","minLength":1},"causationId":{"type":"string","minLength":1},"payload":{"type":"object","properties":{"subscriptionId":{"$ref":"#/components/schemas/WhsId"},"appId":{"$ref":"#/components/schemas/AppId"},"installationId":{"$ref":"#/components/schemas/InsId"},"url":{"type":"string"},"topics":{"type":"array","items":{"$ref":"#/components/schemas/WebhookTopic"}}},"required":["subscriptionId","appId","installationId","url","topics"],"additionalProperties":false}},"required":["_tag","eventId","txId","tenantId","sequence","occurredAt","source","version","actor","correlationId","payload"],"additionalProperties":false},"webhooks.subscription-deletedEncoded":{"type":"object","properties":{"_tag":{"type":"string","enum":["webhooks.subscription-deleted"]},"eventId":{"$ref":"#/components/schemas/EvtId"},"txId":{"$ref":"#/components/schemas/TxId"},"tenantId":{"$ref":"#/components/schemas/TenantId"},"sequence":{"type":"integer","minimum":0},"occurredAt":{"type":"string"},"source":{"type":"string","minLength":1},"version":{"type":"number","enum":[1]},"actor":{"$ref":"#/components/schemas/Actor"},"correlationId":{"type":"string","minLength":1},"causationId":{"type":"string","minLength":1},"payload":{"type":"object","properties":{"subscriptionId":{"$ref":"#/components/schemas/WhsId"}},"required":["subscriptionId"],"additionalProperties":false}},"required":["_tag","eventId","txId","tenantId","sequence","occurredAt","source","version","actor","correlationId","payload"],"additionalProperties":false},"JournalHead":{"type":"object","properties":{"at":{"type":"string"},"sequence":{"type":"integer","minimum":0}},"required":["at"],"additionalProperties":false,"description":"Where a tenant's journal stood at a moment."}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"A tenant JWT: sign in through the auth service, choose the organization, then `GET /api/auth/token`. Tokens last 15 minutes."}}},"security":[],"tags":[{"name":"subscriptions","description":"Where an app is told what happened in a tenant."},{"name":"deliveries","description":"The delivery log: what was sent to the calling app, and how it answered."},{"name":"events","description":"The webhooks append-only event log."}],"servers":[{"url":"https://webhooks.getmanifold.io","description":"Production"}]}