> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ionicfi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# The terminal payment object

> Run a card-present payment for a PaymentIntent on a Terminal and track the attempt to a final status.

<ResponseExample>
  ```json The terminal payment object theme={null}
  {
    "id": "tpr_01JEXAMPLE2K8V4N9C6M1Q7R",
    "object": "terminal_payment",
    "terminal_id": "tmr_01JEXAMPLE2K8V4N9C6M1Q7R",
    "payment_intent_id": "pi_01JEXAMPLE2K8V4N9C6M1Q7R",
    "charge_id": null,
    "amount_requested": 2500,
    "amount_approved": 2500,
    "currency": "usd",
    "status": "pending",
    "failure_code": null,
    "failure_message": null,
    "livemode": false
  }
  ```
</ResponseExample>

A Terminal Payment (`tpr_…`) is one card-present payment attempt on a
[Terminal](/api-reference/terminals). Your server creates it by processing an existing
[PaymentIntent](/api-reference/payment-intents) on a Terminal. The PaymentIntent must be in
`requires_payment_method`, use automatic capture, use USD, and belong to the
same account and mode as the Terminal. Do not attach or confirm a card
PaymentMethod first.

The call returns HTTP `202` before the buyer interacts with the device, so a
`202` means the command was accepted, not that the payment succeeded. Retrieve
the Terminal Payment or consume webhooks until `status` is final. An approved
attempt creates a Charge, referenced by `charge_id`. See
[Accept in-person terminal payments](/guides/in-person-payments) for the full flow. Platforms
follow [In-person payments for connected accounts](/guides/connect-in-person-payments).

## Attributes

<ResponseField name="id" type="string">
  Unique identifier for the terminal payment (`tpr_…`).
</ResponseField>

<ResponseField name="terminal_id" type="string">
  ID of the terminal that took the payment (`tmr_…`).
</ResponseField>

<ResponseField name="payment_intent_id" type="string">
  ID of the PaymentIntent this attempt pays (`pi_…`).
</ResponseField>

<ResponseField name="charge_id" type="string | null">
  Present only after an approved attempt creates a Charge.
</ResponseField>

<ResponseField name="amount_requested" type="integer">
  PaymentIntent amount in minor currency units.
</ResponseField>

<ResponseField name="amount_approved" type="integer">
  Amount approved so far, in minor currency units. 0 until an approval is recorded.
</ResponseField>

<ResponseField name="currency" type="string">
  Three-letter ISO currency code, in lowercase.
</ResponseField>

<ResponseField name="status" type="string">
  `succeeded`: approved; complete the sale. `voided`: authorized and then voided; do not complete the sale. `declined`: explicitly declined; request another tender. `canceled`: interaction canceled or timed out. When `cancellation_requested` is true, the PaymentIntent is also canceled; create a new PaymentIntent if payment is still needed. Otherwise, retry this PaymentIntent only after it returns to `requires_payment_method`, using a new Idempotency-Key. `failed`: known processing failure; show the failure before a new attempt. `unknown`: both the command response and the immediate read-only status check were inconclusive; do not process the order again. Ionic checks the original payment again about 2, 5, 10, 20, 40 and 80 seconds later, then at growing intervals, and updates this payment once the result is confirmed. `pending` or `in_progress`: retrieve this Terminal Payment until final.
</ResponseField>

<ResponseField name="failure_code" type="string | null">
  Stable Ionic detail for a known non-approval. This is intentionally an open string: branch on `status`, use recognized values for richer POS guidance, and fall back to `failure_message` for an unfamiliar value. Raw device responses are not returned. Currently emitted values: - `dispatch_not_started`: Ionic rejected the command before payment processing began. - `processor_error`: Ionic confirmed a final processing failure. - `invalid_routing`: the Merchant's payment setup is invalid. - `pin_processing_error`: PIN processing failed. - `do_not_honor`: the payment received a generic decline. - `insufficient_funds`: the payment was declined for insufficient funds. - `incorrect_pin`: the payment was declined for an incorrect PIN. - `pin_attempts_exceeded`: the PIN retry limit was reached. - `transaction_not_permitted`: the transaction is not permitted for the selected payment setup.
</ResponseField>

<ResponseField name="failure_message" type="string | null">
  Safe Ionic explanation suitable for a POS.
</ResponseField>

See every field in the response of [Retrieve a Terminal Payment](/api-reference/terminal-payments/retrieve-a-terminal-payment).

## Endpoints

| Endpoint | Use it for |
| - | - |
| [Process a PaymentIntent on a Terminal](/api-reference/terminal-payments/process-a-paymentintent-on-a-terminal) | Start a card-present payment for a PaymentIntent. |
| [Retrieve a Terminal Payment](/api-reference/terminal-payments/retrieve-a-terminal-payment) | Check the current status of an attempt. |
| [Request cancellation of an active Terminal Payment](/api-reference/terminal-payments/request-cancellation-of-an-active-terminal-payment) | Ask Ionic to abort an attempt that is still running. |
| [Print a refund receipt on a Terminal](/api-reference/terminal-payments/print-a-refund-receipt-on-a-terminal) | Print a receipt for a succeeded card-present Refund. |

## Statuses

| Status | Meaning | What to do next |
| - | - | - |
| `pending` | The attempt is running. | Retrieve the Terminal Payment until its status is final. |
| `in_progress` | The attempt is running. | Retrieve the Terminal Payment until its status is final. |
| `unknown` | The command response and the immediate read-only status check were both inconclusive. | Keep retrieving the same attempt. Do not process the order again. |
| `succeeded` | The payment was approved. | Complete the sale. |
| `voided` | The payment was authorized, then voided. | Do not complete the sale. Offer another tender if payment is still needed. |
| `declined` | The payment was explicitly declined. | Show `failure_message` and request another tender. |
| `failed` | A known processing failure. | Show the failure, then retry with a new `Idempotency-Key` or use another tender. |
| `canceled` | The interaction was canceled or timed out. | If `cancellation_requested` is `true`, the PaymentIntent is also canceled: create a new PaymentIntent if payment is still needed. Otherwise retry the same PaymentIntent only after it returns to `requires_payment_method`, using a new `Idempotency-Key`. |

Declines and failures are returned as Terminal Payment resources with HTTP
`200`. Branch on `status`, and treat `failure_code` as display detail because new
codes can appear without a new `status` value. The
[failure code table](/guides/in-person-payments#failure-codes) lists the current values.

## Interaction status

`terminal_interaction` reports reader availability and is independent of the
financial `status`.

| Value | Meaning |
| - | - |
| `pending` | Ionic accepted the operation, but the terminal interaction has not started. |
| `active` | The operation may currently occupy the reader. |
| `completed` | The terminal interaction finished and this payment no longer blocks a new payment. Keep retrieving any financially `unknown` result. |

## Rules

* Reusing the same `Idempotency-Key` returns the same HTTP result. Selecting a different Terminal for a PaymentIntent that has an active attempt returns HTTP `409`.
* Retrieval reads Ionic's latest durable state. It does not send a command to the Terminal and never resubmits the sale.
* A cancellation request is not a financial outcome, and HTTP `202` does not mean the payment was canceled. The payment can still be approved after the request. Refund an unwanted late approval separately.
* A Terminal runs one command at a time. A busy Terminal returns `409 TERMINAL_BUSY`. See [Handle API errors](/guides/in-person-payments#handle-api-errors).
* To test without hardware, use the simulated Terminals described in [The Terminal object](/concepts/terminal-object).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.