agreement.transitioned events. Use them when your backend needs to react to agreement lifecycle changes without polling agreement state on a timer.
Treat each activity webhook as a compact signal: verify it, store and dedupe it, acknowledge it, and then read current agreement data from the Agreements API before updating your local mirror.
Before you start
Create a webhook subscription that includesagreement.transitioned:
When activity events are sent
Shodai sendsagreement.transitioned for API-managed agreements owned by the API principal when:
- an agreement deploys and the deployment response includes a post-deploy state
- a mined input changes the agreement state
fromState: "" and inputId: "__deploy". If the post-deploy state is not available yet, Shodai skips the deploy transition event.
Input transition events are sent only when the mined input changes state. If an input is accepted but the agreement remains in the same state, no agreement.transitioned event is emitted for that input.
Payload shape
An activity event includes compact transition data:| Field | Description |
|---|---|
agreementId | Hosted agreement record ID. |
agreementName | Optional human-readable agreement display name. |
templateId | Agreement template ID from the agreement JSON metadata. |
fromState | Previous lifecycle state. Deploy transitions use an empty string. |
toState | New lifecycle state. |
inputId | Input that caused the transition. Deploy transitions use __deploy. |
Reconcile after receipt
After verification and dedupe, read the current agreement data before updating local state:GET /v0/agreements/{id} for the hosted agreement record, GET /v0/agreements/{id}/state for current lifecycle state, and GET /v0/agreements/{id}/inputs for input history.
This pattern keeps your integration resilient when events arrive more than once, arrive after your own write response, or do not contain enough data to update your local model directly.
Filter activity events
Activity webhooks support these filters:| Filter | Matches |
|---|---|
agreementIds | data.agreementId |
templateIds | data.templateId |
inputIds | data.inputId |
fromStates | data.fromState |
toStates | data.toState |
inputIds: ["__deploy"] to receive only deploy activity events for matching agreements and templates.
Idempotency expectations
Webhook delivery is at-least-once. Your receiver should:- store each event by
id - treat a repeated
idas already received - return
2xxafter durable receipt - process reconciliation asynchronously when possible
- make local mirror updates idempotent