Skip to main content
This is the shortest implementation path that matches the current code:
  1. create a case
  2. store the returned caseId
  3. receive case.completed, case.failed, or case.input_needed
  4. resume paused work with POST /cases/{id}/input
  5. poll GET /cases/{id} or fetch attachments when needed

1. Configure Your API Host And Key

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:

Important Notes About Input Submission

  • 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