This is the shortest implementation path that matches the current code:
- create a case
- store the returned
caseId
- receive
case.completed, case.failed, or case.input_needed
- resume paused work with
POST /cases/{id}/input
- poll
GET /cases/{id} or fetch attachments when needed
The codebase does not hardcode a single public hostname. Use the Offload API host for your environment.
All public routes use the same header:
2. Create A Case
This example asks Offload to collect a signed W-9 over email and return structured output when the case completes.
Successful response:
Important Notes About Creation
201 means the case was stored and queued. The first outbound email is sent asynchronously.
maxAttempts is the number of automated follow-up attempts after the initial outreach.
resultSchema only needs to be an object at API validation time. The API does not fully validate that it is a strict JSON Schema document.
- Repeating the same
POST /cases call creates another case. There is no idempotency key on this route.
3. Create A Case From TypeScript
4. Handle Webhook Events
If you set clientWebhookUrl, Offload sends a JSON POST when the case:
- completes
- fails
- pauses for human input
Example handler:
The current implementation sends webhooks with content-type: application/json, but it does not sign them and it does not retry failed deliveries. Use HTTPS, dedupe on event_id, and consider periodic polling reconciliation for important cases.
5. Resume A Paused Case
When Offload needs a human decision, it sends case.input_needed and sets the case to INPUT_NEEDED.
Resume the case with the exact inputRequestId from the webhook:
Accepted response:
202 means the input was queued, not that the case has already resumed.
- The handler immediately marks
inputRequestStatus as RESOLVED before the worker processes the queued event.
- In that short window,
GET /cases/{id} can still show status: "INPUT_NEEDED" together with inputRequest.status: "RESOLVED".
- There is no webhook for “input accepted” or “case resumed”. You only get the next terminal or paused event.
6. Poll A Case
Use polling when:
- you did not set
clientWebhookUrl
- you want to reconcile missed webhook deliveries
- you want to fetch the plain-text transcript on demand
Fetch the transcript:
includeTranscript only enables the transcript when the query value is the literal string true after trimming and lowercasing.
7. Fetch An Attachment
Webhook events and GET /cases/{id} return attachment metadata, not a permanent file URL.
The response includes a fresh downloadUrl plus an expiresAt timestamp. Request the link only when you are ready to fetch the file.
Next Pages