Skip to main content

Worked voice samples

These four flows walk an outbound call from creation to completed-recording retrieval, including the two error shapes you must handle on the way. All requests use your API key (X-API-Key) against https://api.orbit.devotel.io.

1. Place an outbound call

POST /voice/calls initiates an outbound call and returns the new call id and its initial status. 202 is not returned here — a successful initiation responds 201.
cURL
201 Created
status starts as initiated; the lifecycle progresses through the terminal state completed/no-answer/failed (see hangup_reason on the webhook, or GET /voice/calls/{id} below). Poll the status endpoint or listen for the webhook — don’t assume the call is still ringing.

2. Poll the call status

GET /voice/calls/{id} returns the call row with the fields updated as the call progresses.
cURL
200 OK

3. Webhook — call.completed

Register a webhook endpoint (POST /webhooks) subscribed to call.completed so your server receives the terminal status the moment it happens, instead of polling.
POST to your endpoint
The full event list and endpoint-management API live at Webhook events. Field-level definitions (the same payload every webhook carries) are pinned against call.initiated and call.completed there.

4. Retrieve the recording

Once a call shows a recording, GET /voice/calls/{id}/recording returns a signed, time-limited playback URL plus the duration/format and any chapter markers. The url is pre-signed and expires after the expires_at epoch-ms timestamp.
cURL
200 OK
When structured chaptering is enabled, chapters carries [{ start_ms, end_ms, title, summary }] markers; when it is off, it is []. A call that was never recorded returns 404 NOT_FOUND.

Error — unverified caller-id

When the caller-id in from is neither a platform/tenant number you own nor a verified external caller-id, the request is rejected before dispatch.
422 Unprocessable Entity
Fix it by enrolling the number through the verified-caller-id flow (POST /voice/caller-ids/verify + OTP confirm) and retrying, or by picking a number already active on your account.

Beyond the call lifecycle: six more operations, worked

The generator renders the four call-lifecycle flows above with full bodies, but six more voice operations resolve to an empty placeholder envelope — the bare "data": {} shape the sample guard bans — because their OpenAPI 2xx response carries no JSON schema. Each section below replaces that placeholder with the worked { data, meta } envelope the operation actually returns. The Node SDK does not wrap the voice namespace yet, so every TypeScript tab goes through the SDK’s orbit.request escape hatch (the same convention the API recipes guide uses for uncovered resources) — you get the SDK’s auth, retries, and envelope unwrapping against the raw REST path. Python tabs mirror through its SDK’s client.request raw-request method, no requests packaging needed. Use a sandbox key (dv_test_sk_YOUR_KEY) until the flow reads clean, then swap in your live key. Every envelope here follows the four shapes in How to read a worked sample — success carries { data, meta }, failure carries { error, meta } with a stable error.code.

5. Read the affinity-routing strategy

GET /voice/affinity-routing returns your organization’s behavioral-affinity routing config — the pairing objective that routes an inbound contact to the agent best matched to them (customer-segment ↔ agent-affinity fit), not merely the globally best-scoring agent. The response is normalized: a tenant that never configured it gets the disabled default shape (not a 404), so you can render the empty state straight off the response.
agent_profiles maps an agent’s user id to the affinity tags that agent pairs well with (segment, style, value). An untouched tenant reads { "enabled": false, "treatment_percent": 0, …, "agent_profiles": {} } with profile_count: 0 — still a clean 200.

6. Replace the affinity-routing strategy

PUT /voice/affinity-routing replaces the whole config. Only the affinity-routing sub-object is rewritten — every other tenant setting is untouched, and the stored blob is the resolved (clamped, weight-renormalized, tag-normalized) config. The write is audited; the response echoes the canonical shape the router will actually apply, so read it back rather than assuming your input survived as-is.
To turn the affinity arm off, PUT {"enabled": false} — the config stays stored but the router stops consulting it. Body schema violations (a weight outside 0…1, treatment_percent outside 0…100, an unknown key on the strict body) return 422 VALIDATION_ERROR with error.details per field, exactly as pinned in the placeholder-eliminator pinned test for this op. Per-op error shapes: A 404 cannot fire on this pair — an unset config reads as the disabled default shape, and the PUT creates it on first write.

7. Read a call’s deferred AMD decision

GET /voice/calls/{id}/amd returns the Answering Machine Detection decision for a call you placed with amd: true on POST /voice/calls. AMD resolves as live speech, a machine greeting, or unknown; a call placed without the flag has no decision row to read.
While the decision is still open, status reads pending with result: null — poll or take the webhook rather than treating pending as an error. Per-op error shapes:

8. Read a call’s audit annotations

A call’s free-form account / cost-center annotation (PUT /voice/calls/{id}/account-code) lives on the audit row, not the call row itself. GET /voice/calls/{id}/account-code reads the current annotation so your billing-reconciliation loop can assert what the last write left behind — annotation and audit only; no outbound signalling.
A call with no annotation yet returns the same envelope with value: null (and set_by/set_at null) — a clean 200, so branch on value, not on the status code. Per-op error shapes:

9. Read the calls stream page

GET /voice/calls/stream returns one page of the tenant’s call feed for feed-style dashboards. The page is cursor-paginated: keep issuing the same request with the returned cursor until has_more flips false, and treat an empty items array as the end of the feed, never as a failure.
Per-op error shapes: A 404 cannot fire on this read — the feed is tenant-scoped, so an unknown page cursor is the only empty-list condition beyond the end of the feed.

10. List queue callbacks (scheduled dials)

GET /voice/callbacks lists the contact-center callbacks the queue has promised — the scheduled dials an agent or the queue will place — with an analytics summary in the same envelope. Filter by queue_id or status, and cancel a pending one with DELETE /voice/callbacks/{id} (idempotent: already-terminal rows answer 204, unknown ids 404).
Phone numbers are masked on every read (+14155****567 shape), so the list is safe to render in operator UIs and logs. Per-op error shapes:

Queue & agent state round-trips, worked

The generated voice page still renders { "data": {} } for every queue/agent- state round-trip — the CCaaS operator daily path. Twelve of the most-hit queue and agent-state read routes get their worked envelope below. Each shape matches its handler in queue.controller.ts / aux-codes.controller.ts / pause-reason-codes.controller.ts / agent-state-history.controller.ts / conference.controller.ts / voicemail.controller.ts.

11. List the queues

GET /voice/queues returns your org’s queue list with the routing-strategy and live-member snapshot the operator page needs. The summary block totals over the org’s queues so the dashboard’s cross-queue SLA chip stays one call.
POST /voice/queues creates queues; the config editors route through POST /voice/queues + PATCH /voice/queues/{id} writes before GET hydrates.

12. Get the queue detail

GET /voice/queues/{id} returns the queue’s synthesis — config + live member list from the Redis agent registry. The supervisor page reads this when it re-hydrates after the operator clicks a dial pad.
PATCH /voice/queues/{id} mutates the queue config (routing strategy, RNA timeout, SLA policy). The response mirrors the stored shape so the detail page renders from the PATCH round-trip without an extra GET.

13. List queue members

GET /voice/queues/{id}/members enumerates the agent workspace — with total + has_more cursor so the page never re-pulls every agent on a tab re-open.
POST /voice/queues/{id}/members adds a member; PATCH /voice/queues/{id}/members/{memberId} flips status offline — the member editor round-trips on the returned skill_levels/queue_weights snapshots, not a full page refresh.

14. Read the per-queue routing weights

GET /voice/agents/{id}/queue-weights returns the agent’s cross-queue routing weights ({queueId: 1-100} from the Redis registry, or { } when the agent has never pushed). The queue-config editor stays visible on the empty case and the operator fills it inline.
PATCH /voice/agents/{id}/queue-weights MERGES a per-queue delta and returns the same envelope — the editor renders what actually persisted, not the optimistic delta.

15. Read the skill-proficiency map

GET /voice/agents/{id}/skill-proficiency returns the agent’s skill×level matrix from acd_queue_members.skill_levels (levels 1…5). The editor renders this as the live state.
PATCH /voice/agents/{id}/skill-proficiency REPLACES the map — the route echoes the replaced shape on the response, so the editor finalises the save against the wire payload, not the patch operator.

16. Read the state-history timeline

GET /voice/agents/{id}/state-history returns the per-agent transition timeline, ordered changed_at DESC (newest first), windowed by from / to / limit. HR-audit and supervisor pages paginate this.
The audit row’s reason carries the pause reason code. The supervisor and the agent browser both anchor to from/to (HR quarters, supervisor 24-h panel) — paginate with limit (default 500, max 5000).

17. List the pause-reason catalog

GET /voice/agents/pause-reason-codes returns the tenant’s ACD pause-reason codes + the defaults set the FE must not have to synthesize.
POST /voice/agents/pause-reason-codes adds; PATCH /voice/agents/pause-reason-codes/{id} mutates active / display_label / max_seconds — and the audit created_at stays stable so replays stay deterministic.

18. List the AUX codes

GET /voice/aux-codes returns the tenant’s AUX-code taxonomy the agent- softphone away-state picker must render. page + pageSize are server- side so the picker never re-pulls the archive on accident.
POST /voice/aux-codes adds; PATCH /voice/aux-codes/{id} mutates. Absent tenants degrade to items: [] + total: 0, never a 404, so the picker always has a pageable page.

19. List conferences

GET /voice/conferences lists the tenant’s conferences (oldest-first if you pass a sort param). The operator board keeps a soft-deleted filter so a deleted conference never sits stale.
POST /voice/conferences seeds; DELETE /voice/conferences/{id} terminates.

20. Get the conference detail

GET /voice/conferences/{id} returns the conference’s join plus the live participants — the operator view renders this straight off one read.
POST /voice/conferences/{id}/participants adds a leg; DELETE /voice/conferences/{id} ends the parent.

21. Page conference participants

GET /voice/conferences/{id}/participants enumerates the per-leg dial list — the dashboard timeline renders each leg straight off this page.
The per-leg failure_reason / error_code mirror the audit row — the conference reconciliation must assert the same code when the operator’s manager mirrors back.

22. List voicemail greetings

GET /voice/voicemail/greeting returns the tenant’s greeting catalog the admin page renders.
POST /voice/voicemail/greeting adds; POST /voice/voicemail/greeting/tts synthesizes TTS. Untouched tenants render items: [] with defaults: [] — defaults stay safe before the first upload.

Queue appointment booking, worked

The queue-booking pair is public — a hosted booking page calls it without an API key, so the tenant id and queue id sit in the path and the surface is deliberately blind: a queue that has not opted in to public booking returns enabled: false rather than an error, and the booking POST rejects the same way. The full booking-page walkthrough lives in the queue appointment booking guide; the two worked calls below are the whole round-trip. Every authenticated section from here on sticks to the same SDK convention as the lifecycle sections above — TypeScript goes through the SDK’s orbit.request escape hatch and Python mirrors through client.request raw requests (the Node SDK does not wrap these surfaces either). The three-link footer at the bottom gets picked up by the same card that every ## Worked voice samples reader sees:
Node.js — SDK escape hatch ring-group example
Python — client.request raw-request

23. List the bookable slots

GET /public/queues/{tenantId}/{queueId}/availability returns the queue’s published bookable slots over a date window — plus the tenant’s branding, page copy, and timezone — so the hosted booking page renders in one read. from/to (ISO-8601), slot_minutes, and lead_minutes are optional; the window defaults to the next 14 days.
A queue that has not enabled public booking answers with the same status and the body {"data":{"enabled":false},"meta":{…}} — never a 404, so the surface can’t be probed for queue existence.

24. Book the slot

POST /public/queues/{tenantId}/{queueId}/appointments books one slot for the caller’s phone number; the server writes it as a scheduled callback that the queue dials at the chosen time. A slot taken moments before returns 409 with error.code: SLOT_ALREADY_BOOKED; a queue that isn’t accepting public bookings returns 422 with error.code: INVALID_TENANT.
Branch on the deterministic error codes above; a blind retry after a SLOT_ALREADY_BOOKED just burns a different slot.

Ring groups and shared lines, worked

Three loops cover the simultaneous-dial surface: define the group (ring groups), pre-check a nested group edit (cycle check), and track a shared line (create → poll live status). The ring groups guide walks the product-side config end to end.

25. Pre-check a ring group for cycles

POST /voice/ring-groups/validate-cycle is the FE’s optimistic pre-save guard: send the proposed members (and the existing group id on edit, or null on create) and it replies ok: true, or ok: false with the cyclePath that closes the loop — so the save button stays disabled inline instead of 422-ing on submit.
When the walk closes a loop, the same status carries the diagnostic:
200

26. Create a ring group

POST /voice/ring-groups writes the group; the response echoes the stored row plus a non-blocking warnings array (duplicate PSTN members across groups) that the dashboard surfaces as a toast.
Duplicate names return 409; a member that references an unknown SIP credential, a malformed PSTN, or a missing nested group returns 422.

27. Create a shared line

POST /voice/shared-lines creates the tenant-scoped shared line (the extension several operators answer from). The response gives the created line back with its (zero) members — you attach members over the member API next. The shared lines appearance guide covers the operator-side setup.
409 fires when name or extension collides within the tenant.

28. Add a shared-line member

POST /voice/shared-lines/{id}/members attaches one member (a SIP extension value or an extension number the server resolves to the credential). canGrab controls whether the member can steal the live call; sortOrder fixes the member list order the dashboard renders.

29. Poll the shared line’s live status

GET /voice/shared-lines/{id}/status is the dashboard’s “In use” / “Idle” read — safe to poll on a short interval, and the decide-to-offer-Grab guard.
activeCall is null when nobody on the line is mid-call; the Grab button in section 30 stays disabled off that read.

30. Grab the shared line’s call

POST /voice/shared-lines/{id}/grab moves the answered call onto the grabbingMemberValue’s device and returns the from/to pairing the softswitch re-INVITE will move.
A second member firing Grab in the same instant gets 409 (the claim is atomic); a member without canGrab gets 403.

SIP trunks, worked

BYO-carrier trunk provisioning splits across outbound and inbound plus the probe/test pair that proves the registrar before the row is saved.

31. Create an outbound SIP trunk

POST /voice/sip-trunks provisions the outbound leg. Send the registrar host (with optional port, transport, authentication, codecs, maxConcurrent, failoverTrunkId, and the probe verdict metadata probe_status/probe_error that keeps the live status from reading “Unregistered” while the save is fresh). The response is the stored entry with the digest password masked.

32. Create an inbound SIP trunk

POST /voice/sip-trunks/incoming provisions the inbound leg. authMode chooses the gate (ip_allowlist, digest, or both); on digest mode the response carries digestUsername plus the one-time digestPassword — record it immediately, because the server masks it on every later read. The credentials_revealed_once flag marks that the plaintext lives only in this first response.

33. Rotate the inbound trunk’s digest credential

POST /voice/sip-trunks/{id}/credentials/rotate re-issues the digest password on an inbound digest/both trunk. The plaintext is NOT in this response — the server mints a single-use reveal_token the caller fetches once via GET /voice/sip-trunks/{id}/credentials/reveal?token=… inside the 5-minute window; subsequent reads return 410. An ip_allowlist-only trunk 422s.

34. Probe an outbound trunk pre-save

POST /voice/sip-trunks/probe runs a real REGISTER through the probe carrier and returns the verdict (reachable/unreachable) plus the ordered steps that named the failing stage. A failed probe is still a 200 — the verdict travels with the eventual POST /voice/sip-trunks as probe_status.

35. Test a persisted trunk

POST /voice/sip-trunks/{id}/test re-checks a stored trunk. Inbound trunks return a static config verdict (ok / misconfigured + per-issue list); outbound trunks re-run the REGISTER probe and reply with status, latency_ms, the sanitised error, and the steps breakdown — the same shape as section 34, anchored to the trunk id.

36. Place a test call through the trunk

POST /voice/sip-trunks/{id}/test-call dials a destination constrained to an org-owned DID or a platform test number — never an arbitrary number, so the billing surface stays safe. The response returns the Jambonz call sid plus the resolved trunkId/to pair.

Browser softphone, worked

The softphone lifecycle splits into four calls: token mint → SIP WSS credential → outbound dial → the (internal) HMAC validate the gateway runs between them. The voice product picker guide lays out when softphone belongs next to trunked calls.

37. Mint the browser softphone token

POST /voice/softphone/token returns the LiveKit access token plus the deterministic softphone:<tenant>:<user> room the browser softphone connects to; reconnects land in the same room. media_url is canonical — livekit_url stays as a deprecated alias one minor cycle.

38. Issue the SIP WSS credential

POST /voice/softphone/register mints the short-lived SIP credential the WebRTC SDK registers against the SIP-over-WSS gateway. The returned tuple (sipUsername, sipPassword, sipDomain, wssUrl, iceServers) is the deterministic config — an optional wssFallbackUrl shows only when a secondary gateway is provisioned.

39. Originate the outbound softphone call

POST /voice/softphone/dial places the PSTN call and bridges it into the per-user LiveKit room the token minted. The response returns the created call row plus the resolved room_name so the dashboard labels the attempts.

40. Internal HMAC credential validate (gateway-internal)

POST /voice/softphone/internal/validate is the SIP gateway’s credential-double-check — not for browser clients. The gateway verifies the member it minted (username, orgId, expiresAt, password) and gets ok: true back, or a 401 when the HMAC is stale/wrong/revoked.

Webhook disposition, worked

POST /voice/sip-webhook is the platform’s inbound media/SIP disposition receiver — the sender signs each payload with a project-issued JWT, and the router acknowledges with handled: true when the event moved the call-log row forward, or handled: false (+ deduped: true when a re-delivered event hit the dedupe slot).

41. Acknowledge a signature-valid disposition event

A re-delivered event returns handled: false with deduped: true; a SIP participant shape the route doesn’t apply returns handled: false. The envelope stays the same { data, meta } pair as every operation above.

More worked envelopes (sections 42–120 — the null-envelope backfill)

The forty-one sections above plus these ~120 pin the per-route { data, meta } body for the highest-traffic reads and writes the generator still rendered with the literal "data": {} shell. Each numbered section opens with a <Note> route callout so the generator’s route-hinted overlay extraction picks this body over the autogen shell, one route per section.

42. Read an affinity-routing config

GET /api/v1/voice/affinity-routing

43. Update an affinity-routing config

PUT /api/v1/voice/affinity-routing

44. Read an attribute-routing config

GET /api/v1/voice/attribute-routing

45. Update an attribute-routing config

PUT /api/v1/voice/attribute-routing

46. List AMD answers on your calls

GET /api/v1/voice/calls/search

47. Read one call row

GET /api/v1/voice/calls/{id}

48. Download the recording inline

GET /api/v1/voice/calls/{id}/recording

49. List the recordings a call produced

GET /api/v1/voice/calls/aggregate

50. Export the filtered call set

GET /api/v1/voice/calls/export

51. List the SIP trunk inventory

GET /api/v1/voice/sip-trunks

52. Read one SIP trunk

GET /api/v1/voice/sip-trunks/{id}

53. Reveal the trunk credentials once

GET /api/v1/voice/sip-trunks/{id}/credentials/reveal

54. Provision a SIP-webhook POST authentication rule

GET /api/v1/voice/call-forwarding

55. Read my call-forwarding rule as a user

GET /api/v1/voice/call-forwarding/users/{userId}

56. Read the queue’s live counter

GET /api/v1/voice/queues/{id}/live

57. Read the agent’s routing-weights map

GET /api/v1/voice/agents/{id}/queue-weights

58. Patch the agent’s routing weights

PATCH /api/v1/voice/agents/{id}/queue-weights

59. Read the agent’s skill-proficiency map

GET /api/v1/voice/agents/{id}/skill-proficiency

60. Patch the agent’s skill-proficiency map

PATCH /api/v1/voice/agents/{id}/skill-proficiency

61. Read today’s agent-to-state timeline

GET /api/v1/voice/agents/{id}/state-history

62. List voicemail messages

GET /api/v1/voice/voicemails

63. Read a SIP-credential reveal response

GET /api/v1/voice/sip-trunks/{id}/rate

64. Arm the business-continuity reroute

POST /api/v1/voice/business-continuity-reroute/activate

65. Disarm the reroute early

POST /api/v1/voice/business-continuity-reroute/deactivate

66. Read the business-continuity status

GET /api/v1/voice/business-continuity-reroute

67. Create the ACD auto-answer toggle

PUT /api/v1/voice/acd-auto-answer

68. Read the ACD auto-answer toggle

GET /api/v1/voice/acd-auto-answer

69. Read the caller-ids inventory

GET /api/v1/voice/caller-ids

70. Verify a caller-id by SMS challenge

POST /api/v1/voice/caller-ids/verify

71. Re-send the caller-id challenge

POST /api/v1/voice/caller-ids/{id}/resend

72. Confirm a caller-id challenge code

POST /api/v1/voice/caller-ids/confirm

73. Read the aux-code catalog

GET /api/v1/voice/aux-codes

74. Patch an aux-code definition

PATCH /api/v1/voice/aux-codes/{id}

75. List the pause-reason codes

GET /api/v1/voice/agents/pause-reason-codes

76. Patch a pause-reason code

PATCH /api/v1/voice/agents/pause-reason-codes/{id}

77. Read the dial-plan configuration

GET /api/v1/voice/dial-plan

78. Update the dial-plan configuration

PUT /api/v1/voice/dial-plan

79. Read the dialer abandonment ceiling

GET /api/v1/voice/dialer-abandon-ceiling

80. Update the dialer abandonment ceiling

PUT /api/v1/voice/dialer-abandon-ceiling

81. Read the dialing-restrictions map

GET /api/v1/voice/dialing-restrictions

82. Update the dialing-restrictions map

PUT /api/v1/voice/dialing-restrictions

83. Read the directory

GET /api/v1/voice/directory

84. Update the directory

PUT /api/v1/voice/directory

85. Read the maximum-call-duration policy

GET /api/v1/voice/max-call-duration

86. Update the maximum-call-duration policy

PUT /api/v1/voice/max-call-duration

87. Read the recording-policy blob

GET /api/v1/voice/recording-policy

88. Update the recording-policy blob

PUT /api/v1/voice/recording-policy

89. Read the preferred regions list

GET /api/v1/voice/regions/preferred

90. Update the preferred regions list

PUT /api/v1/voice/regions/preferred

91. Read the SIP max-registrations cap

GET /api/v1/voice/sip-max-registrations

92. Update the SIP max-registrations cap

PUT /api/v1/voice/sip-max-registrations

93. Read the skill-proficiency-decay table

GET /api/v1/voice/skill-proficiency-decay

94. Update the skill-proficiency-decay table

PUT /api/v1/voice/skill-proficiency-decay

95. Read the STT provider failover chain

GET /api/v1/voice/stt-provider-chain

96. Set the STT provider failover chain

PUT /api/v1/voice/stt-provider-chain

97. Read the voice-provider BYO credential map

GET /api/v1/voice/voice-provider-credential

98. Register a BYO voice credential

PUT /api/v1/voice/voice-provider-credential/{kind}

99. Activate a pending BYO credential

POST /api/v1/voice/voice-provider-credential/{kind}/activate

100. Revoke a BYO credential

POST /api/v1/voice/voice-provider-credential/{kind}/revoke

101. Rotate a BYO credential on a schedule

POST /api/v1/voice/voice-provider-credential/{kind}/rotate

102. Read the conferencing summary

GET /api/v1/voice/conferences

103. Create a conference

POST /api/v1/voice/conferences

104. Read conference participants page one

GET /api/v1/voice/conferences/{id}/participants

105. Reach the queue SLA hub

GET /api/v1/voice/sla-hub

106. Read the quality aggregates

GET /api/v1/voice/quality/aggregates

107. Read the disaster-recovery drill status

GET /api/v1/voice/emergency-drill

108. Update the disaster-recovery drill

PUT /api/v1/voice/emergency-drill

109. Read the emergency-notification config

GET /api/v1/voice/emergency-notification

110. Update the emergency-notification config

PUT /api/v1/voice/emergency-notification

111. Read the emergency-routing config

GET /api/v1/voice/emergency-routing-config

112. Update the emergency-routing config

PUT /api/v1/voice/emergency-routing-config

113. Attach the E911 address to a number

GET /api/v1/voice/emergency-location/{numberId}

114. Attach an emergency location record

POST /api/v1/voice/emergency-location

115. Resolve whether an address is PSAP-usable

GET /api/v1/voice/emergency-location/{numberId}/resolve

116. Read the emergency callback (PSAP) binding

GET /api/v1/voice/psap-callback/{numberId}

117. Resolve whether the PSAP binding is usable

GET /api/v1/voice/psap-callback/{numberId}/resolve

118. Attach a PSAP callback binding

POST /api/v1/voice/psap-callback

119. Read the per-queue comparison

GET /api/v1/voice/queues/comparison

120. Read the wallboard hub config

GET /api/v1/voice/supervisor/wallboard-hub

Error shapes across these operations

Every operation above answers failures in the same { error, meta } envelope with a stable error.code. The five statuses worth branching on: The general envelope rules (the four shapes, sandbox keys, tagged request ids) live on How to read a worked sample, and the full code catalog sits on the Errors matrix.