Skip to main content

Fetch Requests Tutorial

A fetch request asks an existing worker to supply a credential you don't yet hold — a new First Aid certificate, a renewed registration number, a missing document. The worker receives an email with a secure upload link and submits the details; the request tracks their progress through to completion.

This is a short, copy-paste flow against the REST API: create a request, track it, then nudge, re-issue, or cancel it. Each step links to its full per-endpoint reference.

Before you start

Read API Basics first — it covers base URLs, the Authorization header, IDs, the response envelope, and error shapes that every step here relies on. The examples assume $OHO_BASE and $OHO_TOKEN are set, and that you already have a worker (see the Workers & Credentials tutorial).

Fetch requests carry their own ID shape and authorize against the captureRequest entity type (your token needs access to it):

ResourceID shapeExample
Fetch requestcap_<id>cap_V1StGXR8Z5jdHi6B

1. Create the request

POST /fetch-requests with the target worker and what you're asking for. Identify the worker by exactly one of worker.id (the wkr_ ID) or worker.externalId (your upstream HRIS id). List the credentials you want in requestedCredentialTypes. Optionally add a message to the worker and an expiryDays for the upload link. See Create fetch request for the full field list.

curl -sS -X POST "$OHO_BASE/fetch-requests" \
-H "Authorization: Bearer $OHO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"worker": { "id": "wkr_V1StGXR8Z5jdHi6B" },
"requestedCredentialTypes": ["FIRST_AID", "WWCC_NSW"],
"credentialGuidingTexts": { "FIRST_AID": "Please upload the certificate, not the wallet card." },
"message": "Hi Jordan — please send through your current First Aid and WWCC.",
"expiryDays": 14
}'

The server returns 201 with the generated cap_ ID and a Location header:

{
"data": {
"id": "cap_V1StGXR8Z5jdHi6B",
"type": "fetchRequest",
"attributes": {
"displayName": "Fetch Request — Jordan Avery — 2026-06-29",
"worker": { "id": "wkr_V1StGXR8Z5jdHi6B" },
"message": "Hi Jordan — please send through your current First Aid and WWCC.",
"requestedCredentialTypes": ["FIRST_AID", "WWCC_NSW"],
"credentialGuidingTexts": {
"FIRST_AID": "Please upload the certificate, not the wallet card."
},
"delivery": {
"emailAddress": "jordan.avery@example.com",
"tokenExpiresAt": "2026-07-13T02:14:07Z",
"remindersSent": 0
},
"lifecycle": {
"status": "INITIATED",
"initiatedAt": "2026-06-29T02:14:07Z"
}
}
},
"meta": { "requestId": "f3c1a0e2-..." }
}

Save the ID for the steps that follow:

export REQ="cap_V1StGXR8Z5jdHi6B"
Which credentialType?

requestedCredentialTypes takes the same codes as the rest of the platform (WWCC, Blue Card, teacher registration, AHPRA, NDIS, First Aid, and more). Fetch the live list from List supported credential types. For more complex asks — AND/OR groups, exemptions, or ban checks — send a structured requirements block instead of the flat list; see Create fetch request.

note

Provide exactly one worker identifier and exactly one requirements form — requestedCredentialTypes or requirements, not both. Violations return 400.

2. Track the request

GET /fetch-requests/{requestId} returns the same envelope, with lifecycle.status reflecting where the worker is up to. See Get fetch request.

curl -sS "$OHO_BASE/fetch-requests/$REQ" -H "Authorization: Bearer $OHO_TOKEN"

A request moves through these statuses:

StatusMeaning
INITIATEDCreated; email queued
SENTEmail delivered to the worker
OPENEDWorker opened the upload link
PARTIALLY_COMPLETEDSome, but not all, requested credentials supplied
SUBMITTEDWorker submitted everything requested
COMPLETEDAll requested verifiables have been checked
EXPIREDUpload link lapsed before completion
CANCELLEDWithdrawn by your team (step 6)

To see what the worker has supplied so far, call List submitted credentials at GET /fetch-requests/{requestId}/submissions.

3. List and find requests

GET /fetch-requests lists requests. Filter by status, by workerId, or free-text query (matched across worker name and email); page with page and pageSize. Full parameter list: List fetch requests.

# Everything still awaiting a response
curl -sS "$OHO_BASE/fetch-requests?status=SENT" \
-H "Authorization: Bearer $OHO_TOKEN"

# All requests for one worker
curl -sS "$OHO_BASE/fetch-requests?workerId=wkr_V1StGXR8Z5jdHi6B" \
-H "Authorization: Bearer $OHO_TOKEN"

Returns the standard list envelope with data and a paging meta block. Soft-deleted requests are excluded unless you pass includeDeleted=true.

4. Send a reminder

Worker gone quiet? POST /fetch-requests/{requestId}/remind increments delivery.remindersSent on the existing request. It does not change the status, token, or expiry — the worker keeps the same link. See Send reminder.

curl -sS -X POST "$OHO_BASE/fetch-requests/$REQ/remind" \
-H "Authorization: Bearer $OHO_TOKEN"

Returns 200 with the updated request.

Reminders are mostly automatic

Oho's scheduler sends reminder emails on its own: any request sitting in SENT/OPENED past the reminder window (default 7 days, configurable) gets a reminder, up to a cap (default 3). It does this by re-issuing the request through the INITIATED state, which is what actually dispatches the email. The manual endpoint above bumps the counter for your own tracking; reach for resend (step 5) when you want to force a fresh email to go out now.

If the link has expired — or you want to start the clock fresh — POST /fetch-requests/{requestId}/resend mints a new capture token, extends the expiry, and resets the status to INITIATED. Use the optional expiryDays query parameter to set the new window (default 14). See Resend fetch request.

curl -sS -X POST "$OHO_BASE/fetch-requests/$REQ/resend?expiryDays=7" \
-H "Authorization: Bearer $OHO_TOKEN"

Returns 200 with the request reset to INITIATED and a refreshed delivery.tokenExpiresAt.

Remind vs resend

Remind records a nudge (remindersSent++) against the worker's existing link without changing its state. Resend issues a new link, extends the expiry, and restarts the lifecycle at INITIATED — which is what triggers a fresh email to go out. Reach for resend once a request has expired or when you need an email sent immediately.

6. Cancel the request

Asked in error, or no longer needed? POST /fetch-requests/{requestId}/cancel withdraws it and sets the status to CANCELLED. The worker's link stops working. See Cancel fetch request.

curl -sS -X POST "$OHO_BASE/fetch-requests/$REQ/cancel" \
-H "Authorization: Bearer $OHO_TOKEN"

Returns 200 with the request in status CANCELLED.

Cancel vs delete

Cancelling keeps the request on the worker's history as a withdrawn ask. To remove it from lists entirely, soft-delete it with DELETE /fetch-requests/{requestId} — the record and its history are preserved and resurface with includeDeleted=true.

Where to go next