Document Events and Webhooks
Subscribe to document lifecycle events when your integration should react without polling.
Document AI publishes three versioned event types:
-
document.created.v1 -
document.updated.v1 -
document.deleted.v1
Processing completion, failure, skip, and oversize outcomes appear as document updates. There are no separate document_intelligence.* completion or failure events.
Configure a webhook
Use Shipwell's webhook configuration API to subscribe an HTTPS endpoint to the document events your application needs.
See Use Webhooks for:
- Creating a webhook configuration
- Verifying Shipwell webhook signatures
- Delivery retries and timeouts
- Debugging unsuccessful deliveries
Event payload
Webhook deliveries use the standard Shipwell event envelope. The details object contains the document-specific data.
{
"id": "<event-id>",
"occurred_at": "2026-07-15T12:00:00Z",
"source": {
"user_id": "<user-id>",
"company_id": "<company-id>",
"request_id": "<request-id>",
"publishing_system": "document-store",
"environment": "sandbox"
},
"event_name": "document.updated.v1",
"details": {
"id": "<document-id>",
"resource_type": "document",
"self_link": "/document-store/documents/<document-id>/",
"status": "completed",
"type": "bill_of_lading",
"filename": "bol.pdf",
"description": "Bill of lading for a completed shipment.",
"content_type": "application/pdf",
"size_bytes": 1832102,
"associations": [
{"entity_type": "shipment", "entity_id": "SW-1001"}
],
"old_data": {"status": "processing"},
"new_data": {"status": "completed"},
"run_id": "<run-id>",
"result_count": 1,
"url": "<temporary-download-url>",
"url_expires_at": "2026-07-15T12:15:00Z"
}
}Fields can be absent when they do not apply. For example, run_id and result_count are associated with processing updates, while delete_kind can appear on a delete event.
Treat details.url as a temporary, sensitive convenience URL. Store details.id and request a new download URL when needed.
Event behavior
document.created.v1
Sent after a document is created.
The initial status can be:
-
pendingwhen processing was requested - A stored, non-processing status when no configuration was selected
-
skippedoroversizedwhen the document was stored but was not eligible for processing
AI-generated fields may not be available yet because processing is asynchronous.
document.updated.v1
Sent when document data or processing state changes. Processing outcomes are represented through details.status, commonly:
-
completed -
failed -
skipped -
oversized
Use old_data and new_data when you need to understand the changed fields. On a completed processing update, use run_id to retrieve the run and its results.
document.deleted.v1
Sent after document deletion. The payload identifies the deleted document and can include delete_kind.
Do not attempt to use a temporary download URL from a delete event.
Recommended handler
- Verify the webhook signature using the raw request body.
-
Persist the delivery and return a
2xxresponse promptly. - Process the event asynchronously.
-
Upsert state by
details.id. - Retrieve the current document or run before performing downstream work.
Example routing logic:
def handle_document_event(event):
event_name = event["event_name"]
details = event["details"]
if event_name == "document.updated.v1" and details.get("status") == "completed":
enqueue_result_sync(
document_id=details["id"],
run_id=details.get("run_id"),
)
elif event_name == "document.deleted.v1":
enqueue_document_removal(document_id=details["id"])Delivery safety
Webhook delivery is at least once, and events can arrive out of order.
- Make handlers idempotent.
- Do not assume the event identifier is sufficient to prevent every repeated business action.
-
Compare
occurred_atand retrieve current resource state before applying changes. -
Avoid depending on a strict
created→updated→deletedarrival order. - Keep side effects behind your own idempotency key.