Terminal payments require an Ionic
tmr_… ID owned by the same Merchant and
mode as the PaymentIntent. Every test account receives built-in simulated
tmr_… IDs automatically; Ionic assigns physical Terminal IDs through the
hardware provisioning flow. Send only the Ionic ID; never send a hardware
serial number or device credential. See
the Terminal object for its lifecycle,
connection, and capability states.Before you begin
You need:- a server-side Ionic secret key with
payments:readandpayments:write; - a built-in simulated test Terminal or an assigned physical Terminal that is ready for the requested tender;
- the terminal’s Ionic ID, which starts with
tmr_; - a unique
Idempotency-Keyfor each mutating POST request; reuse a value only to retry the same request. The read-only batch refresh does not use one.
Ionic-Account: $CONNECTED_ACCOUNT_ID on every
request in this guide. It selects the connected account that owns the
PaymentIntent, Terminal, and resulting payment resources. A Merchant using its
own Account key omits that header.
Request physical hardware
Create a provisioning request when a Merchant needs a physical Terminal. The request tracks hardware fulfillment and eventually points to the Ionic Terminal resource used by the payment API. The Terminal object guide explains how to interpret its independent setup, connection, and capability states.1
Create or reuse a Location
Create the business Location where the Terminal will operate, or reuse an
existing
loc_… in the same Merchant and mode.2
Request a Terminal
Use a secret key with Store the returned
terminals:write. Ionic selects and prepares the
appropriate hardware; the request body contains only the Location, a
merchant-facing label, and optional metadata.tprov_… as PROVISIONING_REQUEST_ID.3
Track fulfillment
Retrieve the provisioning request until it becomes The request can move through
ready. If it becomes
requires_action, show the additive required_actions values to the
Merchant and continue retrieving the same request after they are complete.requested, processing,
requires_action, ready, failed, or canceled. A ready request has
a non-null terminal_id.4
Check Terminal readiness
Retrieve the assigned
tmr_… and begin payments only when its lifecycle
status and the requested payment capability are both ready.GET /terminal_provisioning_requests and
Terminal inventory with GET /terminals. Both collections are cursor-paginated
and scoped to the authenticated Merchant and test or live mode.
Test without physical hardware
Every test account automatically owns two Ionic test Locations and three ready simulated Terminals. The fixture catalog is universal, but each Account gets its ownloc_… and tmr_… IDs. This gives a Platform realistic Account and
multi-location isolation without a separate provisioning integration.
The profile configures what the Terminal observes; it does not return a canned
API response. Processing still creates and transitions normal Ionic
PaymentIntent, Terminal Payment, Charge, PaymentMethod, Refund, batch, profile,
item, idempotency, and webhook records. This makes status handling and resource
relationships representative while keeping the card interaction deterministic.
1
List the Account's test Terminals
Use the Platform test key and connected account header. Select a Terminal
by Store the selected
test_profile, not by a hard-coded universal ID—the IDs are unique to
each Account.tmr_… as TERMINAL_ID. List again for each connected
Account; never reuse one Account’s Terminal ID for another Account.2
Create a PaymentIntent
Create a fresh method-neutral PaymentIntent for the logical payment attempt,
exactly as shown in the normal payment flow below.
3
Run the normal Terminal payment call
Call
POST /terminals/{id}/process_payment_intent. No simulator-only
request fields or helper call are needed, so this is the same integration
you use with physical hardware.4
Optionally override one PaymentIntent
Use the test helper only when a focused test needs a result other than the
selected Terminal’s profile. This override wins for the exact Terminal and
PaymentIntent once.Supported override outcomes are
succeeded, voided, declined,
failed, canceled, unknown, and dispatch_not_started. Declined and
failed outcomes require a compatible failure_code.test_profile.
To test reconciliation, set outcome to unknown and include a final
resolution_outcome plus resolution_delay_seconds from 1 through 86400.
Ionic first returns the attempt with an unknown result; retrieve that same
terminal_payment until the configured delay passes. Ionic reconciles the
result automatically, usually within about one second of the configured time.
Never submit a second Sale to resolve an unknown result.
Cancellation uses the normal
POST /terminal_payments/{id}/cancel endpoint. An unresolved unknown
scenario without a configured final result becomes canceled. If the scenario
already has a later resolution_outcome, that result remains authoritative,
which lets you test a late-approval race after cancellation was requested.
Simulate current batches
Configure a durable current-batch situation, then call the same batch refresh endpoint used with a physical Terminal. Keep a profile’sreference stable
and submit that profile again to replace its items for the next observation.
Profiles omitted from an update remain unchanged, so an open batch cannot
disappear. Up to 10 profiles with 1,000 items per profile can be retained.
terminal_batch, settlement-profile,
and batch-item resources. With no configured batch scenario, a simulated
Terminal reports an empty default profile instead of returning an unsupported
operation. The simulator also supports the normal POST /refunds flow for a
succeeded Terminal payment; refund resources and state transitions are handled
by the same Ionic payment lifecycle. When refunds on the Terminal are on for
your account, include terminal_id on a full refund before the batch settles to
void the sale on the Terminal and print its receipt there; see
Refunds on the Terminal.
With automatic refund receipts on, a card-present refund that includes
terminal_id prints its receipt on that Terminal; see
Refund receipts.
Payment flow
1
Create a PaymentIntent
Create the same PaymentIntent used by other Ionic payment flows. Do not
attach a
payment_method, send a payment_token, or confirm it first. The
intent must remain in requires_payment_method, use USD, and use automatic
capture.2
Process it on a terminal
Select the Ionic terminal ID in the route and pass the PaymentIntent ID in
the request. The request has no Credit/Debit selector: the buyer presents
an ordinary card and the eligible route is chosen automatically.If PIN debit applies, the terminal prompts for PIN. The returned Terminal
Payment reports
payment_type as credit or debit once the tender type is
confirmed.3
Inspect the Terminal Payment
HTTP
202 means Ionic recorded the attempt and returned a
terminal_payment; it does not by itself mean the payment was approved.
Complete the order only when status is succeeded.Handle every status
Declines and failures are returned as Terminal Payment resources with HTTP
200. Branch on status; treat failure_code as display detail, because new
codes can appear without a new status value.
Failure codes
failure_code is nullable and appears only when Ionic has a known
nonapproval. These are stable Ionic values; raw device responses are not
returned.
New
failure_code values are additive. Use status as the workflow boundary
and fall back to failure_message when a code is unfamiliar.
Handle API errors
An API error means Ionic could not return a normal Terminal Payment response. Most errors below happen before a Sale is sent, but a timeout or persistence failure can leave the financial outcome uncertain.Retrieve an unresolved attempt
If the result ispending, in_progress, or unknown, retrieve the same
tpr_… resource. Do not process the PaymentIntent again to resolve a timeout.
unknown attempt when the
original payment reaches a confirmed result, and the resulting state is
available through this GET and terminal-payment webhooks. Retrieval never
submits a new Sale, so poll it as often as your integration requires.
Request cancellation
Cancel only an active attempt, and treat cancellation as a request rather than a financial outcome.cancellation_requested: true confirms that Ionic recorded the request.
Continue inspecting status: the payment can still be approved after you
request cancellation. Refund a late approval separately if you no longer want
the payment.
Platforms and connected Merchants
An authorized Platform acting for a connected Merchant adds the delegation header to terminal requests whose API reference listsIonic-Account:
404.
The header is route-specific, not a global account switch. Omit it for direct
Merchant access and for any endpoint that does not document the header.
Test before going live
Use a test-mode key and the Account’s built-in simulated Terminals for automated coverage. Cover an approval, decline, failed dispatch, delayed unknown result, retried request with the sameIdempotency-Key, cancellation, refund, a batch refresh,
and retrieval of the resulting resources. Then run acceptance testing on an
Ionic-assigned physical test Terminal to validate the device, store network,
PIN entry, and live account setup before enabling production hardware.
What’s next
Refund a completed payment
Send
terminal_id with a refund to run it as a card-present refund on a terminal.Read the Terminal object
Interpret a Terminal’s setup, connection, and capability states.
Run it for connected accounts
Process terminal payments for the connected accounts a platform serves.

