> ## 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.

# Process a PaymentIntent on a Terminal

> Prompts one physical Terminal assigned to your account to collect the amount on
an existing PaymentIntent.

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 first attach or confirm a normal card PaymentMethod.

Reusing the same Idempotency-Key safely returns the same HTTP result.
An existing active attempt is returned only when its Terminal and
payment type match this request; a mismatch returns HTTP 409.
If the Terminal's response is ambiguous, Ionic performs a read-only
status check before responding. If the returned Terminal Payment is
still `unknown`, retrieve it; do not process the order again, because
the original payment may still complete.




## OpenAPI

````yaml /openapi/terminal-payments.yaml post /terminals/{id}/process_payment_intent
openapi: 3.0.3
info:
  title: Ionic Terminal Payments API
  version: '2026-08-18'
  description: |
    Process an existing Ionic PaymentIntent, with no payment method attached,
    on a physical Terminal owned by the same Merchant.

    The Terminal route selects card-present collection. Callers do not send a
    `payment_method_type`. The `payment_type` field selects the tender behavior
    requested from the Terminal. Supported values are `credit` and `debit`;
    Debit additionally requires a ready `debit_pin` Terminal capability.

    HTTP 200 means Ionic has recorded the attempt and returned its current
    status. It does not by itself mean that money was approved.
    A POS completes the sale only when `status` is `succeeded`.

    Amounts are integer minor units. Timestamps are Unix epoch seconds. Test
    and live resources are isolated by the mode of the secret key.
servers:
  - url: '{baseUrl}/v1'
    variables:
      baseUrl:
        default: https://api.ionicfi.com
        description: API base URL for the selected environment.
security:
  - secretKey: []
tags:
  - name: Terminal Payments
    description: Run and retrieve card-present payment attempts.
paths:
  /terminals/{id}/process_payment_intent:
    post:
      tags:
        - Terminal Payments
      summary: Process a PaymentIntent on a Terminal
      description: >
        Prompts one physical Terminal assigned to your account to collect the
        amount on

        an existing PaymentIntent.


        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 first attach or confirm a normal card PaymentMethod.


        Reusing the same Idempotency-Key safely returns the same HTTP result.

        An existing active attempt is returned only when its Terminal and

        payment type match this request; a mismatch returns HTTP 409.

        If the Terminal's response is ambiguous, Ionic performs a read-only

        status check before responding. If the returned Terminal Payment is

        still `unknown`, retrieve it; do not process the order again, because

        the original payment may still complete.
      operationId: processTerminalPayment
      parameters:
        - $ref: '#/components/parameters/TerminalId'
        - $ref: '#/components/parameters/IonicAccount'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProcessTerminalPaymentRequest'
            examples:
              credit:
                summary: Collect a credit payment
                value:
                  payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
                  payment_type: credit
              debit:
                summary: Collect a PIN-debit payment
                value:
                  payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
                  payment_type: debit
      responses:
        '200':
          description: |
            The Terminal Payment. Inspect `status`; only `succeeded`
            means the payment was approved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TerminalPayment'
              examples:
                pending:
                  $ref: '#/components/examples/TerminalPaymentPending'
                inProgress:
                  $ref: '#/components/examples/TerminalPaymentInProgress'
                approved:
                  $ref: '#/components/examples/TerminalPaymentSucceeded'
                voided:
                  $ref: '#/components/examples/TerminalPaymentVoided'
                declined:
                  $ref: '#/components/examples/TerminalPaymentDeclined'
                failed:
                  $ref: '#/components/examples/TerminalPaymentFailed'
                canceled:
                  $ref: '#/components/examples/TerminalPaymentCanceled'
                unknown:
                  $ref: '#/components/examples/TerminalPaymentUnknown'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/PaymentOrTerminalNotFound'
        '409':
          $ref: '#/components/responses/TerminalBusy'
        '422':
          $ref: '#/components/responses/TerminalPaymentNotReady'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/TerminalUnavailable'
        '504':
          $ref: '#/components/responses/GatewayUncertain'
      security:
        - secretKey:
            - payments:write
components:
  parameters:
    TerminalId:
      name: id
      in: path
      required: true
      description: Physical Terminal selected by the POS for this checkout.
      schema:
        type: string
        pattern: ^tmr_
      example: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
    IonicAccount:
      name: Ionic-Account
      in: header
      required: false
      description: |
        Merchant ID when an authorized Platform acts for a connected Merchant.
        Omit when authenticating directly as that Merchant.
      schema:
        type: string
        pattern: ^mer_
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: |
        Unique checkout-attempt key. Reuse the same value only when retrying
        the same request body and route.
      schema:
        type: string
        minLength: 1
        maxLength: 255
      example: pos-order-1042-attempt-1
  schemas:
    ProcessTerminalPaymentRequest:
      type: object
      additionalProperties: false
      required:
        - payment_intent_id
        - payment_type
      properties:
        payment_intent_id:
          type: string
          pattern: ^pi_
          description: Existing PaymentIntent in `requires_payment_method`.
          example: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        payment_type:
          type: string
          enum:
            - credit
            - debit
          description: |
            Tender behavior requested from the Terminal. This is not a
            PaymentMethod type. `debit` invokes the terminal's PIN-debit path
            and requires a terminal whose `debit_pin` capability is ready.
    TerminalPayment:
      type: object
      additionalProperties: false
      required:
        - id
        - object
        - merchant_id
        - terminal_id
        - payment_intent_id
        - charge_id
        - livemode
        - amount_requested
        - amount_approved
        - amount_remaining
        - currency
        - payment_type
        - status
        - cancellation_requested
        - cancellation_requested_at
        - failure_code
        - failure_message
        - created_at
        - updated_at
      properties:
        id:
          type: string
          pattern: ^tpr_
        object:
          type: string
          enum:
            - terminal_payment
        merchant_id:
          type: string
          pattern: ^mer_
        terminal_id:
          type: string
          pattern: ^tmr_
        payment_intent_id:
          type: string
          pattern: ^pi_
        charge_id:
          type: string
          nullable: true
          pattern: ^ch_
          description: Present only after an approved attempt creates a Charge.
        livemode:
          type: boolean
        amount_requested:
          type: integer
          format: int64
          minimum: 1
          description: PaymentIntent amount in minor currency units.
        amount_approved:
          type: integer
          format: int64
          minimum: 0
        amount_remaining:
          type: integer
          format: int64
          minimum: 0
        currency:
          type: string
          enum:
            - usd
        payment_type:
          type: string
          enum:
            - credit
            - debit
            - ebt_food
            - ebt_cash
          description: Tender type used for this attempt.
        status:
          $ref: '#/components/schemas/TerminalPaymentStatus'
        cancellation_requested:
          type: boolean
          description: >-
            Whether cancellation was requested. This alone does not mean the
            payment was canceled.
        cancellation_requested_at:
          type: integer
          format: int64
          nullable: true
        failure_code:
          $ref: '#/components/schemas/TerminalPaymentFailureCode'
        failure_message:
          type: string
          nullable: true
          description: Safe Ionic explanation suitable for a POS.
        created_at:
          type: integer
          format: int64
        updated_at:
          type: integer
          format: int64
    TerminalPaymentStatus:
      type: string
      enum:
        - pending
        - in_progress
        - unknown
        - succeeded
        - voided
        - declined
        - failed
        - canceled
      description: >
        `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.

        `pending` or `in_progress`: retrieve this Terminal Payment until final.
    TerminalPaymentFailureCode:
      type: string
      nullable: true
      description: >
        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.
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
            message:
              type: string
  examples:
    TerminalPaymentPending:
      value:
        id: tpr_01JEXAMPLE2K8V4N9C6M1Q7R
        object: terminal_payment
        merchant_id: mer_01JEXAMPLE7A5P9D3F8K2N4Q
        terminal_id: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
        payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        charge_id: null
        livemode: false
        amount_requested: 123
        amount_approved: 0
        amount_remaining: 123
        currency: usd
        payment_type: credit
        status: pending
        cancellation_requested: false
        cancellation_requested_at: null
        failure_code: null
        failure_message: null
        created_at: 1786939200
        updated_at: 1786939200
    TerminalPaymentInProgress:
      value:
        id: tpr_01JEXAMPLE2K8V4N9C6M1Q7R
        object: terminal_payment
        merchant_id: mer_01JEXAMPLE7A5P9D3F8K2N4Q
        terminal_id: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
        payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        charge_id: null
        livemode: false
        amount_requested: 123
        amount_approved: 0
        amount_remaining: 123
        currency: usd
        payment_type: credit
        status: in_progress
        cancellation_requested: false
        cancellation_requested_at: null
        failure_code: null
        failure_message: null
        created_at: 1786939200
        updated_at: 1786939201
    TerminalPaymentSucceeded:
      value:
        id: tpr_01JEXAMPLE2K8V4N9C6M1Q7R
        object: terminal_payment
        merchant_id: mer_01JEXAMPLE7A5P9D3F8K2N4Q
        terminal_id: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
        payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        charge_id: ch_01JEXAMPLEC4V8B2N6M9K3P7
        livemode: false
        amount_requested: 123
        amount_approved: 123
        amount_remaining: 0
        currency: usd
        payment_type: credit
        status: succeeded
        cancellation_requested: false
        cancellation_requested_at: null
        failure_code: null
        failure_message: null
        created_at: 1786939200
        updated_at: 1786939212
    TerminalPaymentVoided:
      value:
        id: tpr_01JEXAMPLE2K8V4N9C6M1Q7R
        object: terminal_payment
        merchant_id: mer_01JEXAMPLE7A5P9D3F8K2N4Q
        terminal_id: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
        payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        charge_id: ch_01JEXAMPLEC4V8B2N6M9K3P7
        livemode: false
        amount_requested: 123
        amount_approved: 0
        amount_remaining: 123
        currency: usd
        payment_type: credit
        status: voided
        cancellation_requested: false
        cancellation_requested_at: null
        failure_code: null
        failure_message: null
        created_at: 1786939200
        updated_at: 1786939212
    TerminalPaymentDeclined:
      value:
        id: tpr_01JEXAMPLE2K8V4N9C6M1Q7R
        object: terminal_payment
        merchant_id: mer_01JEXAMPLE7A5P9D3F8K2N4Q
        terminal_id: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
        payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        charge_id: null
        livemode: false
        amount_requested: 123
        amount_approved: 0
        amount_remaining: 123
        currency: usd
        payment_type: credit
        status: declined
        cancellation_requested: false
        cancellation_requested_at: null
        failure_code: do_not_honor
        failure_message: The payment was declined.
        created_at: 1786939200
        updated_at: 1786939212
    TerminalPaymentFailed:
      value:
        id: tpr_01JEXAMPLE2K8V4N9C6M1Q7R
        object: terminal_payment
        merchant_id: mer_01JEXAMPLE7A5P9D3F8K2N4Q
        terminal_id: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
        payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        charge_id: null
        livemode: false
        amount_requested: 123
        amount_approved: 0
        amount_remaining: 123
        currency: usd
        payment_type: credit
        status: failed
        cancellation_requested: false
        cancellation_requested_at: null
        failure_code: processor_error
        failure_message: payment processing error
        created_at: 1786939200
        updated_at: 1786939212
    TerminalPaymentCanceled:
      value:
        id: tpr_01JEXAMPLE2K8V4N9C6M1Q7R
        object: terminal_payment
        merchant_id: mer_01JEXAMPLE7A5P9D3F8K2N4Q
        terminal_id: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
        payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        charge_id: null
        livemode: false
        amount_requested: 123
        amount_approved: 0
        amount_remaining: 123
        currency: usd
        payment_type: credit
        status: canceled
        cancellation_requested: true
        cancellation_requested_at: 1786939205
        failure_code: null
        failure_message: null
        created_at: 1786939200
        updated_at: 1786939212
    TerminalPaymentUnknown:
      value:
        id: tpr_01JEXAMPLE2K8V4N9C6M1Q7R
        object: terminal_payment
        merchant_id: mer_01JEXAMPLE7A5P9D3F8K2N4Q
        terminal_id: tmr_01JEXAMPLE8H2Q91P4T6K0M3N5
        payment_intent_id: pi_01JEXAMPLEF9W6B3C2D7K4M8N
        charge_id: null
        livemode: false
        amount_requested: 123
        amount_approved: 0
        amount_remaining: 123
        currency: usd
        payment_type: credit
        status: unknown
        cancellation_requested: false
        cancellation_requested_at: null
        failure_code: null
        failure_message: null
        created_at: 1786939200
        updated_at: 1786939350
  responses:
    BadRequest:
      description: Malformed body, identifier, amount, currency, or unsupported tender.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            malformedBody:
              value:
                error:
                  code: INVALID_REQUEST
                  message: invalid request body
            invalidData:
              value:
                error:
                  code: INVALID_DATA
                  message: terminal payment type is not supported
    Unauthorized:
      description: Missing or invalid secret key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missingKey:
              value:
                error:
                  code: AUTHENTICATION_REQUIRED
                  message: API key is required
            invalidKey:
              value:
                error:
                  code: API_KEY_INVALID
                  message: invalid API key
    Forbidden:
      description: >-
        Missing permission, invalid delegation, inactive Merchant, or
        unavailable live capability.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            permissions:
              value:
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  message: insufficient permissions
            inactiveMerchant:
              value:
                error:
                  code: MERCHANT_INACTIVE
                  message: merchant is not active
            liveDisabled:
              value:
                error:
                  code: LIVE_PAYMENTS_NOT_ENABLED
                  message: merchant is not enabled for live payments
    PaymentOrTerminalNotFound:
      description: PaymentIntent or Terminal was not found in this Merchant and mode.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            paymentIntent:
              value:
                error:
                  code: PAYMENT_INTENT_NOT_FOUND
                  message: payment intent not found
            terminal:
              value:
                error:
                  code: TERMINAL_NOT_FOUND
                  message: terminal not found
    TerminalBusy:
      description: >-
        The Terminal is busy with another command, or this PaymentIntent already
        has an active attempt on a different Terminal or tender.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            terminalBusy:
              value:
                error:
                  code: TERMINAL_BUSY
                  message: terminal already has an active command
            paymentProcessing:
              value:
                error:
                  code: PAYMENT_PROCESSING
                  message: payment is currently being processed
    TerminalPaymentNotReady:
      description: PaymentIntent state or Terminal configuration cannot run this payment.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            invalidPaymentState:
              value:
                error:
                  code: INVALID_PAYMENT_STATE
                  message: >-
                    payment intent must require a payment method and use
                    automatic capture
            terminalNotReady:
              value:
                error:
                  code: TERMINAL_NOT_READY
                  message: terminal is not ready for this payment type
    RateLimited:
      description: Request was throttled before a Terminal command was sent.
      headers:
        Retry-After:
          description: Seconds to wait before retrying the identical logical request.
          schema:
            type: integer
            minimum: 0
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: RATE_LIMIT_EXCEEDED
              message: too many requests
    InternalError:
      description: >-
        Unexpected Ionic failure. Do not infer whether a financial command ran
        from this response alone.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: INTERNAL_ERROR
              message: internal error
    TerminalUnavailable:
      description: >-
        Terminal is offline, its payment connection is unavailable, or Ionic
        could not verify readiness before dispatch.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            offline:
              value:
                error:
                  code: TERMINAL_OFFLINE
                  message: terminal is offline
            routeUnavailable:
              value:
                error:
                  code: TERMINAL_CONNECTION_UNAVAILABLE
                  message: terminal payment connection is unavailable
            serviceUnavailable:
              value:
                error:
                  code: SERVICE_UNAVAILABLE
                  message: unable to verify merchant status
    GatewayUncertain:
      description: >-
        The payment may have been submitted, but its final outcome is not known.
        Retrieve the PaymentIntent or Terminal Payment before retrying.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: GATEWAY_UNCERTAIN
              message: >-
                payment outcome unknown — retrieve the existing payment before
                retrying
  securitySchemes:
    secretKey:
      type: http
      scheme: bearer
      bearerFormat: Ionic secret key
      description: Merchant secret key, or a Platform secret key with delegation.

````