Terminal payments require an Ionic
tmr_… ID owned by the same Merchant and
mode as your secret key. You can create a simulated tmr_… with a test key;
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 Location in the same Merchant and mode, identified by
loc_…; - a 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.
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
A simulated Terminal is a durable Merchant resource for local development, CI, staging, and SDK integration tests. Create a test Location and Terminal once, then reuse theirloc_… and tmr_… IDs across test runs. The Terminal is
immediately ready for credit and PIN-debit requests and never creates a
physical provisioning request.
The test helper 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
Create or reuse a test Location
Use a test-mode secret key with Store the returned
locations:write. The key determines the
Location’s mode; do not send livemode in the body. Test and live
Locations are separate resources.loc_… as LOCATION_ID. A Location is Ionic’s record
of your business location, not a hardware identifier. You can list,
retrieve, and update it through the Location API; there is no delete
endpoint.2
Create a simulated Terminal
Use the same test-mode key with Store the returned
terminals:write and the Location from the
previous step.tmr_… as TERMINAL_ID. You do not need to create a
new Terminal for every test or payment.3
Create a PaymentIntent
Create a fresh method-neutral PaymentIntent for the logical payment attempt,
exactly as shown in the normal payment flow below. A scenario is scoped to
one exact PaymentIntent and Terminal.
4
Arm the expected outcome
Arm one scenario before processing the PaymentIntent. This example arms a
decline for insufficient funds.Supported immediate outcomes are
succeeded, voided, declined,
failed, canceled, unknown, and dispatch_not_started. Declined and
failed outcomes require a compatible failure_code.5
Run the normal Terminal payment call
Call
POST /terminals/{id}/process_payment_intent with the same Terminal
and PaymentIntent IDs. The request has no simulator-only fields, so the
same integration works with physical hardware.terminal_payment with
failure_code: dispatch_not_started.
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.
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. For PIN debit, send
payment_type selects the tender behavior on the terminal,
credit or PIN-based debit. It is not a PaymentMethod type."payment_type": "debit". The selected terminal must
have a ready PIN-debit capability.3
Inspect the Terminal Payment
HTTP
200 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 every request:404.
Test before going live
Use a test-mode key and a reusable simulated Terminal 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.

