# Consume a hosted session

`POST /functions/v1/hosted-session-consume`

One atomic exchange, so a replay can never win a second one. Every refusal is a 200 with a named reason, and a token offered under the wrong credentials is burned.

Called by our server when the hosted screen boots — service role, or the merchant's own secret key. Publishable keys are rejected.

```
{ "session_token": "hs_9c1f..." }
```

The exchange is one atomic statement, so a replay can never win a second exchange.

## Refusals are 200, never errors

| reason | Notes |
| --- | --- |
| SESSION_NOT_FOUND | Also returned for a malformed token, so an attacker learns nothing from the difference |
| SESSION_EXPIRED | Carries expires_at |
| SESSION_ALREADY_USED | Carries consumed_at |
| SESSION_MERCHANT_MISMATCH | Wrong merchant credentials for this token |

> A token offered under the wrong merchant credentials is **burned**, rather than left available for a second attempt.

## Success

```
{
  "consumed": true,
  "session": {
    "session_id": "hss_71ac33",
    "merchant_id": "mrc_9f2c",
    "action": "authorize",
    "external_txn_ref": "order-88213",
    "amount_cents": 18900,
    "currency": "USD",
    "brand": "Northwind",
    "metadata": {},
    "created_at": "2026-09-16T12:01:03Z",
    "expires_at": "2026-09-16T12:06:03Z"
  }
}
```

There is no polling and no “get session status” flow. A hosted session is exchanged once and is not a status resource. Hosted sessions emit no webhooks.
