Claim Chaser Docs
Your first claim — from an empty organization to a claim that is ready to dial
Before you start you need an API key with the write scope. If you do not have one, do
Step 0 first — it takes about five minutes.
Time: about ten minutes.
Steps 1–6 are free and safe. Provisioning and checking a claim never places a call and never costs anything — you can run them against a real organization without consequence.
⚠️ Steps 7 and 8 are different. Step 7 makes the organization able to place calls, and Step 8 places one — to whichever carrier you chose in Step 3. If that is a real insurer, we telephone them. While you are learning, use the sandbox carrier named in Step 3 and a throwaway organization.
The mental model
Five things must exist before a claim can be called, and each one depends on the one above it:
office where you bill from — carries your EIN and callback number
└── doctor who bills — carries the NPI
└── carrier which insurer — chosen from our shared catalogue
└── credentialing link "this doctor is in-network with this carrier"
└── claim the thing we chase
The credentialing link is the one people forget. A claim with a perfect office, doctor and carrier still will not be called unless you have explicitly said that doctor is in-network with that carrier. That is Step 4.
Which endpoint should you use for claims?
There are two ways to write a claim. Use POST /api/uploads/claims — it is the integration point,
and this guide uses it throughout. Three reasons, all of which matter more the larger you get:
- It takes batches. A practice-management export is hundreds of rows. One request, one round trip, one thing to retry.
- A batch is all-or-nothing for hard failures only. A row that violates a database constraint (a
missing required field) fails the whole request with a
400and nothing is inserted — a clean rejection to retry, not a half-applied import you have to untangle. A row that is merely unusable (e.g. an unrecognisedclaim_status) is instead reported per row, and the rest of the batch still inserts. - Errors name the row. Validation failures come back with
invalid_claim_indexes, so you know which record in your export to fix rather than bisecting a batch by hand.
POST /api/claims writes a single claim and is the right shape when a person is entering one record
interactively and wants immediate per-field feedback. It is not the shape a nightly sync wants.
The two routes do not accept an identical field set. If you use the single-row route, check the response for
UNKNOWN_FIELDS— it names any field that route will not write, and the fields it covers are not guaranteed to match the batch route's. Anything it declines can be set afterwards withPATCH /api/claims/{id}or a batchaction:"update", though that is two round trips and the claim exists in between, so prefer getting it right in the create call.
Step 1 — Create your office
export KEY="cc_live_YOUR_KEY_HERE"
export BASE="https://app.claimchaser.ai"
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/offices \
-d '{
"name": "Northgate Dental — Ballard",
"address": "210 Northgate Ave, Seattle, WA 98109",
"callback_number": "2065550142",
"ein": "911234567",
"create": true
}'
{"created":true,"id":"e53d2594-dcb2-4a36-8c36-d61cf49ee260"}
Save that id — everything else references it.
| Field | Rule |
|---|---|
name | required |
address | required |
callback_number | required. 10 digits, or 11 if it starts with 1. US numbers only — a non-US number is rejected. This is the number a carrier rep will call you back on |
ein | required. Exactly 9 digits. 12-3456789 and 123456789 both work |
create | see the callout below |
⚠️ You must send
"create": trueWithout it, a brand-new organization gets this and nothing is created:
{"matched":false,"candidates":[],"next":"Re-send with resolve_to:\"<id>\" … or create:true …"}This endpoint is create-or-match: it looks for an existing office with a similar name first, and declines to guess. On an empty organization there is nothing to match, so you always need
create: truethe first time.Leave it off on re-runs. Send the same office again without
createand you get the existing record back — that is what makes your provisioning script safe to re-run:{"matched":true,"id":"e53d2594-…","match_type":"exact"}
Step 2 — Create your doctor
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/doctors \
-d '{
"name": "Dr. Alice Nguyen",
"npi": "1548273942",
"office_id": "e53d2594-dcb2-4a36-8c36-d61cf49ee260",
"create": true
}'
{"created":true,"id":"03806027-bab4-4973-8281-0aa3b051843b"}
| Field | Rule |
|---|---|
name | required |
npi | required. Exactly 10 digits |
office_id | optional, but send it — a doctor with no office is harder to work with later |
create | same as Step 1 |
npiis required here even though the app lets you save a provider without one. If you do not have the NPI yet, look it up free at npiregistry.cms.hhs.gov. Do not invent a placeholder. A made-up NPI passes the format check, reaches the carrier's phone system, and fails there — costing a call that could not have succeeded.
Two doctors cannot share a name inside one organization. If you send a second provider with the same name and a different NPI, you get the first doctor's id back with
"matched": true. Check the returned id is the one you expect before attaching claims to it.
Step 3 — Find your carrier
⚠️ Testing? Use the sandbox carrier.
Name it exactly:
Sandbox Test Carrier (Claim Chaser)curl -s -H "x-api-key: $KEY" "$BASE/api/carriers?search=sandbox"{"carriers":[{"id":"28f3bf20-07bd-4cc5-9228-9a65640d290c", "name":"Sandbox Test Carrier (Claim Chaser)","in_network":false}],"truncated":false}If you pick a real carrier instead, and you later reach Step 8, we will telephone that insurance company about your claim. A real switchboard, a real queue, a real person, and real money. There is no undo and no "test mode" on a real carrier.
The catalogue is the list of insurers we can actually dial. It is not a list of examples. Choose a real carrier only when you are working real claims for a real practice.
Carriers come from a shared catalogue. You do not create them.
Search first, then copy the exact id. For the rest of this guide we use the sandbox carrier:
curl -s -H "x-api-key: $KEY" "$BASE/api/carriers?search=sandbox"
{"carriers":[{"id":"28f3bf20-07bd-4cc5-9228-9a65640d290c",
"name":"Sandbox Test Carrier (Claim Chaser)","in_network":false}],"truncated":false}
When you move to production, search for the insurer the practice actually bills — but be precise, because the catalogue holds national payers and their state plans, and they are different companies to dial:
curl -s -H "x-api-key: $KEY" "$BASE/api/carriers?search=delta"
{"carriers":[
{"id":"80a9021c-…","name":"Delta Dental","in_network":false},
{"id":"914eeb45-…","name":"Delta Dental of California","in_network":false},
{"id":"8e2a79e7-…","name":"Delta Dental Of Washington","in_network":false}
], "truncated":false}
Nothing in the API tells you which of those the practice's remittance advice means — match it against
what is printed on the EOB. in_network tells you whether your organization is already linked.
⚠️ If you use
POST /api/carrier-requests, checkmatch.exactbefore trusting the resultThat endpoint matches by similarity, and a name that is not in the catalogue can come back matched to a different insurer:
{"matched":true,"carrier_id":"5418cd3b-…","carrier_name":"EMI Health", "match":{"exact":false,"score":0.727}} ← this was a request for "Acme Health"Only use
carrier_idwhen"exact": true. Otherwise search the catalogue by hand.An exact name is safe and case-insensitive:
{"matched":true,"carrier_id":"8e2a79e7-…","carrier_name":"Delta Dental Of Washington", "match":{"exact":true,"score":1}}
If your carrier genuinely is not in the catalogue, POST /api/carrier-requests files a request for us
to add it, and you get status:"pending" with no carrier_id. We fire a carrier.request_resolved
webhook when it is ready. You cannot withdraw a request once filed, so search before you request.
Step 4 — Credential the doctor with the carrier
This is the step that makes a claim callable. It asserts the provider is in-network.
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/doctor-carriers/turn-on \
-d '{
"doctor_id": "03806027-bab4-4973-8281-0aa3b051843b",
"carrier_id": "28f3bf20-07bd-4cc5-9228-9a65640d290c",
"kind": "customer"
}'
{"ok":true,"doctor_carrier":{"id":"dbb8ded6-…","active":true, …}}
kindis required and must be"customer". Omit it and you get a400listing internal values you cannot use. Safe to call twice — it re-activates rather than duplicating.
Only link carriers the provider is genuinely in-network with. We call only what you link here. Linking a carrier the provider is not credentialed with produces an out-of-network answer — a call that could never have succeeded.
Step 5 — Upload the claim
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/uploads/claims \
-d '{
"action": "insert",
"claims": [{
"claim_number": "NG-4471",
"patient_name": "Marcus Webb",
"date_of_birth": "1978-11-03",
"subscriber_id": "DDWA88213",
"patient_zip": "98107",
"patient_phone": "2065550188",
"insurance_phone": "7066618538",
"date_of_service": "2026-05-14",
"billed_amount": 1240.00,
"claim_status": "Denied",
"carrier_id": "28f3bf20-07bd-4cc5-9228-9a65640d290c",
"office_id": "e53d2594-dcb2-4a36-8c36-d61cf49ee260",
"doctor_id": "03806027-bab4-4973-8281-0aa3b051843b"
}]
}'
The response is the inserted row. Confirm the fields you care about actually landed:
subscriber_id = 'DDWA88213' patient_zip = '98107' patient_phone = '2065550188'
billed_amount = 1240 claim_status = 'Denied'
claim_statusis matched case-insensitively
"Denied","DENIED","denied"and"Denied "all resolve to the same status — casing and surrounding whitespace are normalised, so an uppercase PMS export is fine.A value the API doesn't recognise is not rejected: it is dropped, the claim keeps the dialable default (
Open), and the ignored value is reported on the upload response inignored_status_values— an array of{ row, claim_number, value }objects naming the row and the word we dropped, so the rest of the upload still lands and you can see exactly what was ignored. The recognised statuses include:Open·Pending·Denied·Payment Pending·Paid·No Claim on File·Incorrect Claim Details·Duplicate ClaimIf a status was dropped, patch it later with
action:"update".
Hard failures reject the whole batch; unusable rows don't. Rows that are individually unusable — for
example an unrecognised claim_status — are reported per row and the rest of the batch still inserts. But a
row that violates a database constraint (a missing required field) fails the whole request with a 400 and
nothing is inserted, rather than writing a partial batch you cannot reason about. Send as many claims as you
like in one call.
Insert is idempotent. Sending the same claim again returns the existing claim's id instead of
creating a duplicate — matched on claim_number, with a fallback for claims that lack one — so a
request you are unsure landed is safe to retry.
Step 6 — Confirm the claim is ready to dial
curl -s -H "x-api-key: $KEY" "$BASE/api/claims/CLAIM_ID/callable"
{"callable":false,"dispatch_blockers":["COOLDOWN","VOICE_OFF","CARRIER_HOURS"],
"checked_at":"2026-08-10T07:46:12.158Z"}
callable: falseis usually not a problem — but read the blockers before you waitBlockers fall into three groups, and the difference is what you do next.
1 · Fix your claim — these are about your data
Blocker Meaning MISSING_FIELDSthe claim lacks data a call needs STATUS_NOT_DIALABLEclaim_statusisn't a dialable value (e.g. a terminal status likePaid)NO_CALLABLE_PHONEno usable insurance_phone, and none resolvable from the carrierPAIDa payment amount is recorded, so we will not chase it 2 · Wait — these clear on their own
Blocker Clears when CARRIER_HOURSthe carrier's calling hours start HOLIDAY_WEEKEND_FLOORthe next business day COOLDOWNthe cooldown window since the last call elapses 3 · Someone must act — this one NEVER clears by waiting
Blocker What to do VOICE_OFFCalling is switched off for this organization. Switch it on with your API key — see the command below. ⚠️
VOICE_OFFwill not clear on its own — stop pollingNo amount of waiting changes it. You do not need the app, a person, or approval. Your existing
write-scope key switches it on in one request:curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" \ $BASE/api/voice-settings -d '{"enabled": true}'{"success":true,"enabled":true}The field is
enabled— sendingvoice_onreturns400 {"error":"enabled must be a boolean"}.⚠️ This arms the dialer for the whole organization, not just the claim you are testing, and calls cost money. Read Step 7 before you run it — that is where this belongs in the sequence, and it explains what turning it on actually does.
The claim above is correctly provisioned. Its blockers are
COOLDOWN,VOICE_OFFandCARRIER_HOURS— nothing about the claim's data is wrong. Two clear by themselves;VOICE_OFFis waiting on you, and Step 7 is where you deal with it.
You can also rehearse the actual dispatch. This runs every eligibility check but never dials and never bills:
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/make-call \
-d '{"claim_id":"CLAIM_ID","dry_run":true}'
{"success":true,"dry_run":true,"status":"would_be_blocked",
"dispatch_blockers":["VOICE_OFF","CARRIER_HOURS"],
"message":"Dry run: eligibility verified; a real call would currently be blocked by: VOICE_OFF, CARRIER_HOURS. No call was placed and nothing was billed.",
"plan":{"claim_id":"…","carrier_name":"Sandbox Test Carrier (Claim Chaser)",
"to_number":"+17066618538","from_number":"+18338537038"}}
Check plan.to_number — that is the number we will actually dial. It is derived from the
insurance_phone you supplied, so if it looks wrong, your insurance_phone is wrong.
dry_run requires the calls:write scope. If your key is write-only, use the /callable check
above instead — it needs only read.
Step 7 — Turn on calling
⚠️ This is the step where it stops being free
Everything up to here was inert. This step makes the organization able to place real calls to real insurance carriers, and those calls cost money. It affects every claim in the organization that is already callable — not only the one you have been testing.
If you are learning, do this in a throwaway organization. If this is a real practice, make sure they expect calling to start today.
Your claim is provisioned, but a new organization cannot dial until calling is switched on. This is off by default and stays off until you enable it — deliberately, so that nobody's dialer starts itself.
This is the VOICE_OFF blocker from Step 6. You can clear it yourself with the key you already
have — no app, no support ticket, no approval:
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" \
$BASE/api/voice-settings -d '{"enabled": true}'
{"success":true,"enabled":true}
Check the current state at any time:
curl -s -H "x-api-key: $KEY" $BASE/api/voice-settings
{"enabled":false,"schedule_last_turned_on_at":null,"schedule":{"enabled":false,"on_time":null,"off_time":null,"days":[],"timezone":null}}
| Field | Notes |
|---|---|
enabled | boolean, required. This is the field name — sending voice_on returns 400 {"error":"enabled must be a boolean"} |
| scope needed | write (you do not need calls:write to switch calling on) |
Re-check your claim and VOICE_OFF is gone:
{"callable":false,"dispatch_blockers":["COOLDOWN","CARRIER_HOURS"]}
⚠️ What turning this on actually does
It arms every claim in the organization that is already callable, not just the one you are testing. There is no confirmation prompt and no dry run for this switch. Before you enable it:
- Check what would go out —
GET /api/claimsand inspect thecallabilityarray, or check individual claims withGET /api/claims/{id}/callable. - Make sure the practice expects calling to start. This spends their money.
Calls are bounded by your key's daily call cap — the number you chose when you minted the key,
default 50, maximum 500. When a key reaches it, make-call returns:
{"error":"This API key has reached its daily call cap. Try again after 00:00 UTC.",
"code":"API_KEY_DAILY_CAP_REACHED","daily_call_cap":50,"used_today":50}
There is currently no way to read your cap back from the API. It is shown on the Developer page when you mint the key and appears in the
429body once you hit it — but no endpoint or response header reports it, andGET /api/usage/summaryreports call minutes, not calls remaining. Write your cap down when you create the key.
Turning it back off — do not skip this
Same endpoint, {"enabled": false}:
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" \
$BASE/api/voice-settings -d '{"enabled": false}'
This is not optional housekeeping. An organization left with calling on keeps dialing anything that becomes callable — including claims you upload later, in a different session, for a different reason. If you enabled calling to test, turn it off in the same sitting.
Step 8 — Place the call
⚠️ This dials. Confirm you are on the sandbox carrier (Step 3) before running it. On a real carrier this telephones an insurance company.
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" \
$BASE/api/make-call -d '{"claim_id":"CLAIM_ID"}'
{"success":true,"status":"initiated","message":"Call initiated for Sandbox Testpatient",
"call_sid":"SCL_DWWSTFnu96Cr","conversation_id":"conv_4001kzpawh07ftf9daz0012q7yza",
"call_id":"2beb9289-c3fc-4aea-b883-bbd5bb855a6f",
"claim_id":"5c8b5023-36da-4914-b427-0d66628789ac","to_number":"+17066618538"}
status: "initiated" means the dispatch succeeded — the call is now running. Keep call_id.
Watch it to completion
curl -s -H "x-api-key: $KEY" "$BASE/api/calls/CALL_ID"
It reports "call_status": "in_progress" with "duration": "0:00" until the call ends. Poll every
20–30 seconds. Do not treat a long-running call as a failure — see the timing signal below.
⚠️ What the sandbox carrier actually does today
The sandbox line currently does not reach a representative. The agent dials, navigates the menus, arrives at the transfer point, and is held there until the call times out at about ten minutes.
Three consecutive calls, placed 2026-08-10:
| Call | call_status | Duration |
|---|---|---|
| 1 | completed | 10:00 |
| 2 | completed | 10:01 |
| 3 | completed | 9:30 |
This is the test line's behaviour, not a fault in your integration. Your dispatch worked. If you see this, nothing is wrong with your key, your claim, or your code.
The timing signal — how to tell the two apart
A call that runs to ~10 minutes did not reach anybody. That duration is the reliable discriminator, and it is the one you should build on.
Do not rely on
call_status. All three calls above report"completed".completedmeans the telephone call ended, not that anything was learned. Nor/api/calls/stats, which reported"successRate": 100after three calls that reached nobody.
Reading the outcome
After the call, check what was actually learned:
curl -s -H "x-api-key: $KEY" "$BASE/api/claims/CLAIM_ID/denial-reasons"
curl -s -H "x-api-key: $KEY" "$BASE/api/claims/CLAIM_ID/claim-statuses"
For all three calls above, denial_reasons came back empty and claim_status was unchanged:
{"success":true,"denial_reasons":[]}
Empty denial_reasons after a ~10-minute call is the signature of a call that reached nobody.
That combination — long duration, completed, nothing extracted — is what a held call looks like
from the API.
The sandbox proves the call path, not the result path. Every sandbox call reaches nobody and extracts nothing, so a rehearsal here exercises dispatch, hold, and completion — but never a populated result. That means you cannot validate your result-parsing code against the sandbox: it always returns an empty
denial_reasons, so a parser that "passes" here first meets the real, populated shape in production. Build your parser against the documented response shapes, not the sandbox's empty payload.
ai_summary is null for keyed callers regardless of outcome; read results from denial-reasons
and claim-statuses.
What a successful extraction looks like has NOT been observed and is deliberately not documented here. The sandbox line has not completed a call with a representative in the period we tested. Rather than describe a response shape nobody has seen, this section documents only what was actually measured. When the sandbox reliably reaches a representative, this page gets the real example.
The sandbox carrier is never dialled automatically
GET /api/claims/{id}/callable reports INTERNAL_TEST_CARRIER for sandbox claims:
{"callable":false,"dispatch_blockers":["INTERNAL_TEST_CARRIER","COOLDOWN"]}
That means the claim is excluded from the automatic calling queue — by design, so sandbox claims
never dial on their own. It does not stop POST /api/make-call. All three calls above were
dispatched while /callable reported blockers.
/callabledescribes the automatic queue.make-calldispatches directly. A blocker there does not necessarily mean a direct dispatch will refuse —COOLDOWNandINTERNAL_TEST_CARRIERboth appeared and the call went out anyway. Use themake-calldry run to rehearse a direct dispatch.
When you have finished
Turn calling back off (Step 7) so the organization is not left armed.
Register a webhook — the step this walkthrough skips, and production needs
Everything above polls (…/callable, …/denial-reasons) because a walkthrough runs once. In production you don't poll — you register a webhook and we tell you when a call completes. Do this before you depend on calls in production, so the call.completed event actually reaches you.
It is a browser step on the Developer page (app.claimchaser.ai/developer) — it comes after you already hold a key, and there is no API to create an endpoint. Register an HTTPS URL, copy the signing secret it shows once (you can't retrieve it later — rotate if you lose it), and you'll receive call.completed (plus claim.status_changed and carrier.request_resolved if you add them to event_types). Verify each delivery's signature and respond 2xx within 10 seconds. ⚠️ An endpoint that fails for 24 hours is auto-disabled and must be re-enabled in the browser — it does not resume on its own. Full contract, envelope, and signature code: API guide §8.
Cleaning up test data
If you were experimenting, you can delete claims you created:
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/claims/delete \
-d '{"claim_ids":["CLAIM_ID_1","CLAIM_ID_2"]}'
{"archived_count":0,"deleted_count":2,"ids_skipped_no_ownership":[]}
Claims that have already been called are archived rather than deleted, so call history is never
lost. Ids you do not own are reported in ids_skipped_no_ownership and left alone.
There is no delete for offices or doctors. Create those deliberately — a test doctor is permanent. Use an obviously-named throwaway organization if you want to experiment freely.
The whole thing, as one script
export KEY="cc_live_YOUR_KEY_HERE"; export BASE="https://app.claimchaser.ai"
OFFICE_ID=$(curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/offices \
-d '{"name":"Northgate Dental — Ballard","address":"210 Northgate Ave, Seattle, WA 98109","callback_number":"2065550142","ein":"911234567","create":true}' \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
DOCTOR_ID=$(curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/doctors \
-d "{\"name\":\"Dr. Alice Nguyen\",\"npi\":\"1548273942\",\"office_id\":\"$OFFICE_ID\",\"create\":true}" \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["id"])')
# search, then copy the exact id you want — do not guess.
# This is the SANDBOX carrier. Swap it for a real insurer only when working real claims.
curl -s -H "x-api-key: $KEY" "$BASE/api/carriers?search=sandbox"
CARRIER_ID="28f3bf20-07bd-4cc5-9228-9a65640d290c" # Sandbox Test Carrier (Claim Chaser) — safe to dial
curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/doctor-carriers/turn-on \
-d "{\"doctor_id\":\"$DOCTOR_ID\",\"carrier_id\":\"$CARRIER_ID\",\"kind\":\"customer\"}"
CLAIM_ID=$(curl -sX POST -H "x-api-key: $KEY" -H "Content-Type: application/json" $BASE/api/uploads/claims \
-d "{\"action\":\"insert\",\"claims\":[{\"claim_number\":\"NG-4471\",\"patient_name\":\"Marcus Webb\",\"date_of_birth\":\"1978-11-03\",\"subscriber_id\":\"DDWA88213\",\"patient_zip\":\"98107\",\"insurance_phone\":\"7066618538\",\"date_of_service\":\"2026-05-14\",\"billed_amount\":1240.00,\"claim_status\":\"Denied\",\"carrier_id\":\"$CARRIER_ID\",\"office_id\":\"$OFFICE_ID\",\"doctor_id\":\"$DOCTOR_ID\"}]}" \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["data"][0]["id"])')
curl -s -H "x-api-key: $KEY" "$BASE/api/claims/$CLAIM_ID/callable"
Verified end to end on an empty organization: office → doctor → carrier → credentialing → claim →
callable returning only VOICE_OFF, CARRIER_HOURS, COOLDOWN.
Provenance of this page
Written by running it end to end on a brand-new organization on 2026-08-10. Every request and response shown is real output from that run, not a constructed example.
Steps 1–7 were verified on organization b677f41d, provisioned from empty.
Step 8 reflects three live calls placed against Sandbox Test Carrier (Claim Chaser) on
2026-08-10 at 17:17, 17:28 and 17:39 UTC. All three held at the transfer point and ended at
10:00 / 10:01 / 9:30 with no representative reached and no denial reasons extracted.
The successful-extraction path is not documented here because it was not observed. A budget of eight calls was authorised with a stop rule of "stop once both shapes are seen"; testing was halted after three when it became clear the sandbox line has not completed a call with a representative since mid-July. Earlier durations exist in the call history but are four weeks old on a line that has behaved differently since, so they are deliberately not presented here as what to expect. This section will be completed from a real observation when the sandbox reliably reaches a representative.