Skip to main content
A referral changes status many times between the moment you create it and the moment a report is ready. Status changes are not a post-scan event: most of them happen while we are still authorizing, contacting the patient, and scheduling. This page lists every status you can receive, explains what each one means, and says which ones are worth wiring logic to.

Two different status fields

The API returns status in two places and they describe different things. A referral with two visits tracks each one separately, so a referral can have one booked visit and one still waiting on authorization.

The visit lifecycle

Not every referral takes every hop. The gates before ready_to_book depend on the line of business, and a visit can leave the happy path at any point.

Before booking

Scheduled

At and after the exam

Other outcomes

Which statuses to act on

Three moments usually matter to an integration:
  1. booked — tell the patient where and when. Read visits[].location and visits[].start_time from the same payload.
  2. report_uploaded — a report exists. Pull the PDF with GET /api/v2/order_documents/report.
  3. sent_to_rp — someone on your side needs to unblock the referral.
Visit invoice_ready means reporting is finished for that visit. It is not the signal to pull payments. Payments are a referral-level concern: once the top-level status is no longer pending or canceled, partners with payment read enabled can keep listing them with GET /api/v2/referrals/{referral_id}/payments. New payments can arrive months later. The workers’ compensation example is on Workers’ compensation and payers. Treat the rest as progress information you can surface but should not gate on. Statuses never move backwards through the reporting phases, so you can store the latest one you have seen. New statuses may be added over time, so ignore any string you do not recognize rather than failing.

Referral-level status

The top-level status tracks the case commercially rather than clinically. These are the values with a meaning outside Scan: Other values may appear on this field. They are internal accounts-receivable states and carry no integration meaning, so do not branch on them. invoice_ready appears at both levels but means different things. On visits[].status, reporting is complete for that visit. On the top-level status, the referral’s case is ready for billing. Payment pulls belong on the referral-level field. Skip pending and canceled. invoice_ready, invoice_sent, closed, and the other accounts-receivable values are when listing payments makes sense, and new rows can still appear months after the first invoice-ready event.

Receiving changes

You have two options, and they work well together: subscribe to the webhook for push updates, and poll when you need a snapshot on demand.

Webhook

We POST to the webhook_url on your api_credentials record every time a visit status changes. The full payload is on Status changed, and Webhooks covers the event catalog, retries, and delivery ordering across all three events.

Verify the signature

Read the request body as raw bytes before parsing JSON. Compute HMAC-SHA256 over "{timestamp}.{raw_body}" with the signing secret shown on the API access tab, then compare it to the digest after v1= using a constant-time comparison. Reject timestamps older than five minutes to limit replay attacks.
The body carries a stable event_id, the new status, a changes.status array of [previous, current], the visit_id, an occurred_at timestamp, and a full referral snapshot so you rarely need a follow-up call.
Return HTTP 2xx as soon as you have stored the event, and do the rest of your work afterward. We retry failed deliveries, so the same event can arrive more than once — use event_id to discard duplicates.

Polling

Ask for the current state whenever you need it.
Full payload: Returns a referral by ID. Do not poll for the internal steps between milestones. Wait for the next webhook or take a snapshot when your own workflow needs one.

Notification delivery

Separately from visit status, you can track the emails and texts Scan sends the patient about a referral, such as intake questions, booking confirmations, and appointment reminders. This is delivery metadata only. Recipients, subjects, message bodies, and provider failure text are never returned on either route. Both routes are off by default and are enabled independently of each other and of visit-status delivery, so you can take one without the other. Ask Scan to turn on what you need:

Delivery statuses

pending means we have queued the message and dispatched means we have handed it to the email or SMS provider. Everything after that comes from the provider’s own callbacks, so the two channels do not share a vocabulary. How far a message gets depends on what the provider reports back, so not every notification reaches every status. As with visit status, ignore any value you do not recognize rather than failing.

Webhook

Notification events go to the same webhook_url and are signed the same way, so the verification code above works unchanged. The event header is what differs: You receive one event when the notification is created and one for every status change after it. On that first event changes.status is [null, "pending"].
Delivery is at least once, so deduplicate on event_id. Full payload: Notification status changed.

Pull the history

Ask for every notification attached to a referral and its visits, newest first.
visit_id is set when the message is about a specific visit and null when it is about the referral as a whole. Results are paginated with page and per_page, which defaults to 20.