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

# Test with a simulated terminal

> Create a simulated terminal on a sandbox account to test in-person payment flows without a physical terminal.

export const CopyValue = ({children}) => {
  const [copied, setCopied] = useState(false);
  const getText = node => {
    if (node == null || typeof node === "boolean") return "";
    if (typeof node === "string" || typeof node === "number") return String(node);
    if (Array.isArray(node)) return node.map(getText).join("");
    if (node.props && node.props.children) return getText(node.props.children);
    return "";
  };
  const text = getText(children);
  const copy = () => {
    navigator.clipboard.writeText(text).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }).catch(err => console.error("Failed to copy:", err));
  };
  return <button type="button" onClick={copy} title={copied ? "Copied" : "Copy"} className="group/copy-button backdrop-blur" style={{
    display: "inline-flex",
    alignItems: "center",
    gap: "0.4em",
    padding: "0.1em 0.45em 0.1em 0",
    margin: 0,
    borderRadius: "0.375rem",
    font: "inherit",
    fontVariantNumeric: "tabular-nums",
    lineHeight: 1.4,
    cursor: "pointer",
    whiteSpace: "nowrap"
  }}>
      <span>{children}</span>
      {copied ? <svg width="16" height="11" viewBox="0 0 16 11" fill="none" xmlns="http://www.w3.org/2000/svg" class="fill-primary dark:fill-primary-light">
          <path d="M14.7813 1.21873C15.0751 1.51248 15.0751 1.98748 14.7813 2.2781L6.53135 10.5312C6.2376 10.825 5.7626 10.825 5.47197 10.5312L1.21885 6.28123C0.925098 5.98748 0.925098 5.51248 1.21885 5.22185C1.5126 4.93123 1.9876 4.9281 2.27822 5.22185L5.99697 8.9406L13.7188 1.21873C14.0126 0.924976 14.4876 0.924976 14.7782 1.21873H14.7813Z">
          </path>
        </svg> : <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 text-gray-400 group-hover/copy-button:text-gray-500 dark:text-white/40 dark:group-hover/copy-button:text-white/60">
          <path d="M14.25 5.25H7.25C6.14543 5.25 5.25 6.14543 5.25 7.25V14.25C5.25 15.3546 6.14543 16.25 7.25 16.25H14.25C15.3546 16.25 16.25 15.3546 16.25 14.25V7.25C16.25 6.14543 15.3546 5.25 14.25 5.25Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          </path>
          <path d="M2.80103 11.998L1.77203 5.07397C1.61003 3.98097 2.36403 2.96397 3.45603 2.80197L10.38 1.77297C11.313 1.63397 12.19 2.16297 12.528 3.00097" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
          </path>
        </svg>}
    </button>;
};

A simulated terminal lets you test in-person payments on a sandbox account without a physical terminal. You register it the same way as a physical terminal, but with a special serial number.

<Info>
  Simulated terminals are available on sandbox accounts (`T` prefix) only.
</Info>

## Create a simulated terminal

[`POST /v1/accounts/{aid}/terminals`](/api-reference/account-terminals/aid_account_management_terminals_post)

Set `device_serial_number` to `SIMULATED-{account_id}-` followed by a 3-digit number, for example `SIMULATED-T12345678-001`.

```bash Request wrap theme={null}
curl -X POST https://api.dintero.com/v1/accounts/T12345678/terminals \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "device_serial_number": "SIMULATED-T12345678-001",
    "store_id": "oslo-center"
  }'
```

The terminal is `ACTIVE` immediately. You do not need to activate it.

Keep `terminal_id` from the response. Use it as `order.store.terminal_id` when you create a payment.

## Create a payment

Create a [terminal session](/docs/checkout/in-person/creating-terminal-session) with the simulated terminal's `terminal_id` in `order.store.terminal_id`. The simulated terminal answers automatically. Set `order.amount` to one of the [test amounts](#payment-responses) to choose the outcome.

[`POST /sessions-profile`](/api-reference/session/checkout_session_profile_post)

```bash Request wrap theme={null}
curl -X POST https://api.dintero.com/v1/accounts/T12345678/payments/sessions-profile \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": {
      "return_url": "https://yourpos.example.com/payment/return",
      "callback_url": "https://yourpos.example.com/payment/callback"
    },
    "order": {
      "amount": 39900,
      "currency": "NOK",
      "merchant_reference": "order-12345",
      "items": [
        {
          "id": "sku-coffee-001",
          "line_id": "1",
          "description": "Premium Coffee Beans 1kg",
          "quantity": 2,
          "amount": 39900,
          "vat_amount": 4275,
          "vat": 12
        }
      ],
      "store": {
        "id": "oslo-center",
        "terminal_id": "T12345678-T0010",
        "payout_destination_id": "seller-1"
      }
    },
    "configuration": {
      "channel": "in_store",
      "publish": [
        {
          "channel": "push",
          "type": "terminal"
        }
      ]
    },
    "profile_id": "default"
  }'
```

This example uses `399.00` NOK, so the payment is approved with a Visa card.

## Payment responses

A simulated terminal answers a payment automatically. The session amount decides the outcome and the card brand.

| Amount | Outcome |
| - | - |
| <CopyValue>9901.00</CopyValue> | The payment is declined. |
| <CopyValue>9902.00</CopyValue> | The terminal reports a different amount than requested, and the transaction fails. |
| <CopyValue>9903.00</CopyValue> | The terminal reports a different currency than requested. |
| <CopyValue>9904.00</CopyValue> | The terminal does not respond, and the transaction fails. |
| <CopyValue>9905.00</CopyValue> | The payment is approved with a BankAxept card. |
| <CopyValue>9906.00</CopyValue> | The payment is approved with a Mastercard card. |
| Any other amount | The payment is approved with a Visa card. |

<Note>
  Amounts are shown in major units. In the API, send them in minor units, for example `990100` for `9901.00`.
</Note>

## Refunds and terminal operations

You can [refund](/api-reference/transactions/transactions_id_refund_post) a captured transaction from a successful simulated-terminal payment. For `seitatech.in_person` refunds, include `terminal_id`; the simulated terminal approves automatically.
You can also send [terminal operations](/docs/checkout/in-person/terminal-operations) to a simulated terminal.

The simulator does not provide failure scenarios for refunds or terminal operations, but invalid requests can still return API errors.

## Find simulated terminals

Filter by `device_model=SIMULATED`:

[`GET /v1/accounts/{aid}/terminals`](/api-reference/account-terminals/aid_account_management_terminals_get)

```bash Request wrap theme={null}
curl https://api.dintero.com/v1/accounts/T12345678/terminals?device_model=SIMULATED \
  -H "Authorization: Bearer <TOKEN>"
```


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