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

# Creating a terminal session

> Build the request body for an in-person card payment on a Dintero terminal, including store identifiers, sale, and refund examples.

A terminal session is a regular Checkout session with three additions:

1. A [payment profile](/docs/checkout/payment-profiles) that enables the `seitatech.in_person` payment method.
2. The `order.store` identifiers that route the payment to a specific terminal.
3. A `publish` configuration that auto-initiates the payment on the terminal.

The sections below cover each piece in order, then bring them together in a [full request](#sale-full-request).

## Endpoint

```http theme={null}
POST https://checkout.dintero.com/v1/sessions-profile
Authorization: Bearer <token>
Content-Type: application/json
```

See [POST /sessions-profile](/api-reference/session/checkout_session_profile_post) for the full schema.

## 1. Enable the payment method (payment profile)

In-person payments are enabled on a [payment profile](/docs/checkout/payment-profiles) in Dintero Backoffice → **Settings** → **Payment Profiles**.

Enable **Seitatech In-person** on the profile you reference with `profile_id`, and the session accepts terminal payments without any payment-method configuration in the request body.

<Info>
  Managing payment methods through profiles means you can add or change methods without redeploying integration code. Avoid sending a hardcoded `configuration.seitatech` block on the request - let the profile drive the payment method.
</Info>

## 2. Route to a terminal (`order.store` identifiers)

The payment profile toggles the payment method on; `order.store` says which physical terminal the payment runs on. The terminal ID belongs in `order.store.terminal_id`.

```json theme={null}
{
  "order": {
    "store": {
      "id": "oslo-center",
      "terminal_id": "T0292",
      "payout_destination_id": "seller-1"
    }
  }
}
```

The three fields are required together for in-person payments:

| Field                               | Description                                                                                                                                                              |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `order.store.id`                    | Your merchant store identifier - the `store_id` you sent when creating the store, the same one you already use in the payment-link flow. Not the Dintero-generated `id`. |
| `order.store.terminal_id`           | The `terminal_id` returned when the terminal was registered (for example `P11223351-T0013`). Must be enrolled and linked to the store.                                   |
| `order.store.payout_destination_id` | The `payout_destination_id` linked to the store.                                                                                                                         |

<Info>
  The `order.store.id` you use today in the payment-link flow is fine to keep using - in-person payments use the same store identifier. You just need to add `terminal_id` and `payout_destination_id` alongside it.
</Info>

## 3. Auto-initiate the payment on the terminal (`publish`)

Add a `publish` push/terminal configuration to the session request to auto-initiate the payment on the terminal as soon as the session is created.

```json theme={null}
{
  "configuration": {
    "publish": [
      {
        "channel": "push",
        "type": "terminal"
      }
    ]
  }
}
```

This works whether `seitatech.in_person` is the only enabled payment method or there are other payment methods on the payment profile. The `publish` configuration auto-initiates the payment on the terminal in both cases.

## Sale: full request

This example combines all three pieces to create a session that immediately triggers a payment on terminal `T0292` at store `oslo-center` for 399.00 NOK. The payment profile referenced by `profile_id` has Seitatech In-person enabled, and the `publish` configuration auto-initiates the payment on the terminal.

```json lines highlight={21-35} theme={null}
{
  "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": "T0292",
      "payout_destination_id": "seller-1"
    }
  },
  "configuration": {
    "publish": [
      {
        "channel": "push",
        "type": "terminal"
      }
    ]
  },
  "profile_id": "your_profile_id"
}
```

<Info>
  Amounts are in the smallest unit of the currency. `39900` is 399.00 NOK.
</Info>

## After you create the session

### Cancelling a payment

Once Dintero starts the transaction on the terminal, you can cancel it in two ways:

* **From the terminal** — the customer or operator cancels directly on the device.
* **Via the API** — call [POST /sessions/\{session\_id}/cancel](/api-reference/session/checkout_session_cancel_post) to cancel the session programmatically.

If the payment is successfully cancelled, the transaction is created with status `DECLINED`.

### Receiving the result

Use the `callback_url` and webhooks to know when the transaction is authorized and captured. Terminal payments use auto-capture by default. See [Checkout webhooks](/docs/checkout/checkout-webhooks) and [transaction management](/docs/checkout/transaction-management).

## Refund

`seitatech.in_person` supports both full and partial refunds. The refund
requires a `terminal_id` in the request body, and the cardholder must be
present at the terminal to approve by tapping their card.

Refunds use the standard [refund endpoint](/api-reference/transactions/transactions_id_refund_post):

```http theme={null}
POST https://checkout.dintero.com/v1/transactions/{transaction_id}/refund
Authorization: Bearer <token>
Content-Type: application/json
```

```json theme={null}
{
  "amount": 19950,
  "reason": "Partial return",
  "terminal_id": "T0292",
  "items": [
    {
      "line_id": "1",
      "amount": 19950,
      "quantity": 1
    }
  ]
}
```

### Refund flow

1. Your server sends the refund request. The API returns `202 Accepted` and the
   transaction receives an `INITIATE_REFUND` event while the status remains `CAPTURED`.
2. The terminal prompts the cardholder to approve the refund by tapping their card.
3. The refund completes when the cardholder approves, or is voided if they cancel on the terminal.

### Terminal requirements

The terminal must be active on the same `payout_destination_id` as the original transaction. It does not have to be the same terminal that processed the original payment.

A valid `terminal_id` always returns `202 Accepted`. If the terminal is offline, the `INITIATE_REFUND` event expires after 120 seconds and the transaction is updated with a failed refund event.

<Info>
  Use `callback_url` with `report_event=REFUND` or a [webhooks subscription](/docs/checkout/checkout-webhooks) to receive a notification when the refund status is updated.
</Info>

## Quick reference: answers to common integration questions

| Question                            | Answer                                                                                                                                                                                                                                                                                                                     |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| How do I enable in-person payments? | Enable Seitatech In-person on a [payment profile](/docs/checkout/payment-profiles) in Backoffice and reference it with `profile_id`.                                                                                                                                                                                       |
| Where does `terminal_id` go?        | `order.store.terminal_id`.                                                                                                                                                                                                                                                                                                 |
| Is `order.store.id` enough?         | Yes - reuse the same store ID you already send. Just add `terminal_id` and `payout_destination_id` alongside it.                                                                                                                                                                                                           |
| How do I trigger a sale?            | Create the session against an in-person payment profile with the `order.store` identifiers and a `publish` push/terminal configuration. The terminal prompts automatically.                                                                                                                                                |
| How do I cancel a payment?          | Cancel from the terminal, or call [POST /sessions/\{session\_id}/cancel](/api-reference/session/checkout_session_cancel_post) via the API. The transaction status will be `DECLINED`.                                                                                                                                      |
| How do I refund?                    | [POST /v1/transactions/\{transaction\_id}/refund](api-reference/transactions/transactions_id_refund_post). Both full and partial refunds are supported. Include `terminal_id` in the request body — the cardholder must approve on the terminal.                                                                           |
| When is the refund complete?        | When the cardholder approves on the terminal. A valid `terminal_id` always returns `202 Accepted`. If the terminal is offline, the `INITIATE_REFUND` event expires after 120 seconds and the transaction is updated with a failed refund event. Use `callback_url` with `report_event=REFUND` or webhooks to get notified. |
