Unattended PCI capture in the IVR builder
The DTMF Input node in the IVR builder has a PCI capture mode built for pay-by-phone menus with no agent on the call: an after-hours self-service balance line, a callback-led payment flow, an agent-free billing IVR. When capture mode is on, the caller types their card on the keypad, recording pauses for that window, and the raw digits never reach logs, transcripts, or your flow context — only the digit count and a per-call fingerprint are kept. If a live agent is on the call instead, use the agent-assisted flow covered in Secure payment capture on the live softphone — this page covers the unattended path only.1. When unattended capture is the right tool
Choose the IVR path when the entire payment happens inside the menu and no person participates:- After-hours self-service. A caller reaches your number outside business hours, hears “press 1 to pay your balance,” and types the card while recording pauses. No agent is staffed, so no agent can be descoped — the menu itself must be the trust boundary.
- Callback-led pay. Your system calls the customer back at a confirmed time and walks straight into a capture node.
- Agent-free billing IVRs. Recurring invoice or top-up lines where the caller self-enters a card or PIN every time.
2. Configure it from the IVR builder
In the dashboard, go to Voice → IVR Builder and open your flow (or start a new one — see Design IVR flows on the visual builder).- Drag a DTMF Input node onto the canvas and click it to open the config panel.
- Set the collection shape for a card field: Max Digits (up to 20
for a full card number), Timeout, and Finish on Key
(
#is the usual terminator). For a full capture, use one DTMF Input node per field — card number, expiry, CVV. - Toggle PCI capture mode (secure entry) on.
- Optionally set Tokenizer URL to your payment service provider’s
(PSP) tokenization endpoint — for example
https://payments.example.com/tokenize. The digits are exchanged once against this URL; its opaque reply token is the only value a downstream node can read, via the{{pci_token}}template placeholder. Leave the URL empty to pause recording and mask the digits without tokenizing.
3. Publish preflight
The builder’s preflight validation (the Validate button, which also runs on publish) rejects a malformed tokenizer URL, so a bad literal never ships to the live snapshot. An unparseable URL fails validation with an issue shaped like:4. Runtime semantics — what the platform actually does
Once a published flow reaches a PCI capture node on a live call:- Recording pauses. When the route records the call, recording is paused immediately before the digits are collected and resumed on the continuation — including error paths, so a call is never left with recording silently paused. If the number’s route never started recording, the pause/resume pair is skipped.
- The digits are masked end to end. The platform stores only the
digit count and a salted, per-call fingerprint. The raw entry never
lands in logs, in the call’s flow context, or in transcripts, and
downstream
{{dtmf_input}}placeholders are explicitly cleared so they can never resolve to the captured digits. - Optional token exchange, on your edge. When the node carries a
tokenizer URL, the digits are POSTed once to that URL — your PSP’s
PCI-scoped tokenization endpoint — before they are dropped. The URL
passes an SSRF guard (internal addresses are refused), the request
has a 5-second budget, and the response must be JSON with a top-level
string
tokenfield. The token is stored as{{pci_token}}for downstream nodes (HTTP Request, Send Message, webhooks). - Failure fails closed. An SSRF block, timeout, non-2xx reply, or a response with no token ends the capture with a polite hangup — the digits stay dropped, recording resumes, and nothing half-captured is stored.
5. Bind the capture to a commerce charge
The capture on the call produces a masked, verified summary. Bind it to a priced charge from your backend withPOST /api/v1/commerce/secure-payment/charge. The capture proof is
derived server-side from the call’s stored session — the fields you send
are consistency hints, and any hint that disagrees with the stored
masked summary fails closed. Only a completed capture can bind.
card_last4 must be exactly four digits — send a full card number
anywhere in this flow and the request is rejected at validation. Your
PSP settles the opaque token out of band; subscribe to
commerce.secure_payment.charge_bound to notify your order system when
a charge binds. See Webhook events.
6. Tenant-owned security posture
Masked-DTMF capture is a scope-reduction control you opt into per node — it defaults off. The platform handles only masked digits: the raw card number never persists anywhere on Orbit, and the token exchange runs against an endpoint you operate. That shape keeps Orbit outside your cardholder data environment; it does not by itself make any party PCI DSS compliant.- The PCI scope of the full flow is owned by you: your tokenizer endpoint, your PSP, and your qualified security assessor determine where your boundary lands.
- Keep capture nodes collecting card data only — routing menus, account lookups, and confirmations stay on ordinary DTMF Input nodes.
- Confirm your tenant’s recording-consent and PCI scope obligations with your assessor, and document the control in your own policy. See PCI DSS posture.
7. Limits
- A full card number is never accepted on any platform endpoint — a PAN
sent as the
card_last4hint is rejected at validation. The platform stores digit count plus a salted fingerprint, nothing more. - There is no SIP-trunk or AI-agent pass-through for captured digits: collection runs on the platform’s own voice path, and the only value that travels downstream is the tokenizer’s opaque reply token.
- Tokenizer requests are bounded (5 seconds, response size capped) and fail closed — a slow tokenizing endpoint ends the call rather than holding the caller indefinitely.
8. Troubleshooting
- Publish is blocked with “PCI capture: tokenizer URL is not a valid URL.” The tokenizer URL does not parse as a URL with a host. Fix it in the node’s config panel and re-validate; an empty field is allowed.
- Callers hear “we were unable to process your input” and the call
hangs up. The tokenizer exchange failed closed: the URL is
unreachable, timed out past 5 seconds, answered non-2xx, returned a
body without a top-level string
token, or the SSRF guard refused it (internal address). Check your tokenizer endpoint’s reachability and response shape. - The digits arrive but nothing is tokenized. The tokenizer URL is
empty — capture still masked and paused recording, but no exchange
ran. Set the URL if downstream nodes need
{{pci_token}}. - Capture behaves oddly on a non-bridged leg. PCI capture is an in-call flow step: it runs on the answered leg the flow controls. A leg that is mid-transfer or pure SIP-trunk transit without the flow’s control does not present a gather point — route through a DTMF Input node on the answered call. For the related agent-assisted codes, see Troubleshooting: secure-payment capture failures.
See also
- Secure payment capture on the live softphone — the agent-assisted counterpart.
- Design IVR flows on the visual builder — the canvas this guide configures.
- Build and ship your first IVR flow — the DSL/API contract behind the canvas.
- PCI DSS posture — the compliance surface for card flows.