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

# Override a Terminal payment scenario

> Overrides the built-in profile with exactly one durable outcome for
this simulated Terminal and the specified PaymentIntent. The next new
`process_payment_intent` command matching both IDs consumes the
override. Retries of that already consumed command remain idempotent,
but a different payment attempt cannot reuse it.

Only one unconsumed override can exist for the same Terminal and
PaymentIntent. Without one, the Terminal uses its `test_profile`.




## OpenAPI

````yaml /openapi/terminal-testing.yaml post /test_helpers/terminals/{id}/payment_scenarios
openapi: 3.0.3
info:
  title: Ionic Terminal Testing API
  version: '2026-09-02'
  description: |
    Every test Account automatically owns the same built-in test topology:
    three Account-scoped simulated Terminals across two test Locations. List
    them with `GET /terminals` and select the `approved`, `declined`, or
    `delayed` Terminal by its `test_profile` field.

    Process a normal test PaymentIntent through
    `POST /terminals/{id}/process_payment_intent`; no test-helper call is
    required. The helpers in this API are optional exact-PaymentIntent
    overrides for cases beyond a Terminal's built-in profile. Your POS uses
    the same Terminal Payment integration when it moves to physical hardware.
servers:
  - url: '{baseUrl}/v1'
    variables:
      baseUrl:
        default: https://api.ionicfi.com
        description: API base URL for the selected environment.
security:
  - secretKey: []
tags:
  - name: Terminal Testing
    description: Override built-in Terminal behavior for focused automated tests.
paths:
  /test_helpers/terminals/{id}/payment_scenarios:
    post:
      tags:
        - Terminal Testing
      summary: Override a Terminal payment scenario
      description: |
        Overrides the built-in profile with exactly one durable outcome for
        this simulated Terminal and the specified PaymentIntent. The next new
        `process_payment_intent` command matching both IDs consumes the
        override. Retries of that already consumed command remain idempotent,
        but a different payment attempt cannot reuse it.

        Only one unconsumed override can exist for the same Terminal and
        PaymentIntent. Without one, the Terminal uses its `test_profile`.
      operationId: createTerminalPaymentScenario
      parameters:
        - $ref: '#/components/parameters/TerminalId'
        - $ref: '#/components/parameters/IonicAccount'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTerminalPaymentScenarioRequest'
            examples:
              approved:
                summary: Approve immediately
                value:
                  payment_intent_id: pi_R7pA3nB9qK2mX5sJ4wF8tL6h
                  outcome: succeeded
              decline:
                summary: Decline for insufficient funds
                value:
                  payment_intent_id: pi_R7pA3nB9qK2mX5sJ4wF8tL6h
                  outcome: declined
                  failure_code: insufficient_funds
              delayedDecline:
                summary: Return unknown, then resolve as declined
                value:
                  payment_intent_id: pi_R7pA3nB9qK2mX5sJ4wF8tL6h
                  outcome: unknown
                  resolution_outcome: declined
                  resolution_delay_seconds: 2
                  failure_code: do_not_honor
      responses:
        '201':
          description: The armed one-shot override.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TerminalPaymentSimulation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/TerminalOrPaymentIntentNotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/InvalidState'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - secretKey:
            - terminals:write
components:
  parameters:
    TerminalId:
      name: id
      in: path
      required: true
      description: Merchant-owned simulated Terminal ID.
      schema:
        type: string
        pattern: ^tmr_[0-9A-Za-z]{14}$
      example: tmr_R7pA3nB9qK2mX5
    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_[0-9A-Za-z]{14}$
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: Reuse only when retrying the same route and request body.
      schema:
        type: string
        minLength: 1
        maxLength: 255
  schemas:
    CreateTerminalPaymentScenarioRequest:
      type: object
      additionalProperties: false
      required:
        - payment_intent_id
        - outcome
      properties:
        payment_intent_id:
          type: string
          pattern: ^pi_[0-9A-Za-z]{24}$
          description: Test-mode PaymentIntent owned by the same Merchant.
        outcome:
          $ref: '#/components/schemas/TerminalPaymentSimulationOutcome'
        failure_code:
          $ref: '#/components/schemas/TerminalPaymentSimulationFailureCode'
        resolution_outcome:
          type: string
          enum:
            - succeeded
            - voided
            - declined
            - failed
            - canceled
          description: >-
            Final result for an `unknown` scenario. Omit for every other initial
            outcome.
        resolution_delay_seconds:
          type: integer
          minimum: 0
          maximum: 86400
          description: >-
            Required and greater than zero when `resolution_outcome` is set;
            otherwise omit it.
    TerminalPaymentSimulation:
      type: object
      additionalProperties: false
      required:
        - id
        - object
        - merchant_id
        - terminal_id
        - payment_intent_id
        - livemode
        - outcome
        - consumed
        - created_at
      properties:
        id:
          type: string
          format: uuid
        object:
          type: string
          enum:
            - terminal.payment_simulation
        merchant_id:
          type: string
          pattern: ^mer_[0-9A-Za-z]{14}$
        terminal_id:
          type: string
          pattern: ^tmr_[0-9A-Za-z]{14}$
        payment_intent_id:
          type: string
          pattern: ^pi_[0-9A-Za-z]{24}$
        livemode:
          type: boolean
          enum:
            - false
        outcome:
          $ref: '#/components/schemas/TerminalPaymentSimulationOutcome'
        failure_code:
          $ref: '#/components/schemas/TerminalPaymentSimulationFailureCode'
        resolution_outcome:
          type: string
          enum:
            - succeeded
            - voided
            - declined
            - failed
            - canceled
        resolution_available_at:
          type: integer
          format: int64
          description: Unix epoch seconds when a delayed unknown result can resolve.
        consumed:
          type: boolean
        consumed_at:
          type: integer
          format: int64
          description: >-
            Unix epoch seconds when a process command first consumed the
            scenario.
        created_at:
          type: integer
          format: int64
    TerminalPaymentSimulationOutcome:
      type: string
      enum:
        - succeeded
        - voided
        - declined
        - failed
        - canceled
        - unknown
        - dispatch_not_started
      description: |
        The result the simulated payment reports. `unknown` can remain
        unresolved or resolve later. `dispatch_not_started` simulates a
        failure that occurs before payment processing begins.
    TerminalPaymentSimulationFailureCode:
      type: string
      enum:
        - do_not_honor
        - insufficient_funds
        - incorrect_pin
        - pin_attempts_exceeded
        - transaction_not_permitted
        - processor_error
        - invalid_routing
        - pin_processing_error
      description: |
        Required for `declined` and `failed` final outcomes. Declines accept
        `do_not_honor`, `insufficient_funds`, `incorrect_pin`,
        `pin_attempts_exceeded`, or `transaction_not_permitted`. Failures
        accept `processor_error`, `invalid_routing`, or
        `pin_processing_error`. Omit it for every other final outcome.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
            message:
              type: string
  responses:
    BadRequest:
      description: Invalid JSON, field value, resource mode, or scenario combination.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: >-
        Inactive Merchant, invalid delegation, or missing `terminals:write`
        permission.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    TerminalOrPaymentIntentNotFound:
      description: >-
        The Terminal or PaymentIntent was not found in the authenticated
        Merchant and test mode.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Idempotency or resource uniqueness conflict.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InvalidState:
      description: >-
        An unconsumed scenario already exists or the simulated Terminal is not
        ready.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: Too many requests.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Unexpected server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    secretKey:
      type: http
      scheme: bearer
      bearerFormat: Ionic test secret key
      description: >-
        A test-mode Merchant secret key, or an authorized Platform test key with
        delegation.

````