---
title: "Mint Embed Session"
method: POST
path: "/v1/embed-sessions"
tags: ["Embed Sessions"]
---

# Mint Embed Session

`POST /v1/embed-sessions`

## Request

- Base URL: `https://api.sandbox.usenash.com`
- URL: `https://api.sandbox.usenash.com/v1/embed-sessions`
- Auth: none declared

Mint an Embed Session for one widget, one parent origin, and an explicit set of resources. Returns the browser envelope: `client_secret`, `expires_at`, `session_id`, `api_region`. Forward it to your page as-is; the client secret is the only value that authenticates the widget, and it is returned once.

Pass `refresh_session_id` to replace a live session before it expires. A replacement may narrow the parent's scopes and resources or keep them; widening requires a fresh mint.

Denials are deliberately uniform: `FORBIDDEN` covers every refusal, so a failed request never reveals whether a resource exists. Quote the `X-REQUEST-ID` response header when asking Nash why a specific call was denied; it is present on success and failure alike, and error bodies repeat it as `RequestID`.

## Request body

- EmbedSessionMintRequest: Body of `POST /v1/embed-sessions`. `extra="forbid"`: this endpoint mints an authorization capability, and the one thing worse than rejecting a typo is accepting `scope` (singular) and quietly granting nothing.
  - `widget` string, required: Widget identifier, e.g. `live_map` (`live-map` is accepted).
  - `scopes` string[], required: Scopes to grant, e.g. `['live_map:read']`. Must be granted for the widget.
  - `resources` object, required: The exact resources this session may read, e.g. `{'delivery_ids': ['del_1']}`.
  - `parent_origin` string, required: The page origin that will host the widget. Must match an allowed origin exactly.
  - `ttl` integer, nullable: Requested lifetime in seconds. Defaults to 900.
  - `refresh_session_id` string, nullable: Session id (`wes_…`) to replace. The replacement may narrow the parent's scopes and resources or preserve them; it can never widen them. Omit for a fresh mint.

## Response `200`

OK

- EmbedSessionEnvelope: The mint response, and the entire browser contract (PLAT-22260). The host backend forwards this verbatim to its page; it is not expected to add, rename, or reshape anything. Four fields, each earning its place: * `client_secret` — the only value that authenticates the browser. * `expires_at` — so the page can refresh *before* a request fails rather than discovering expiry as a broken widget. * `session_id` — non-secret. The browser's cache key and the id that shows up in logs and support tickets, which is exactly why it is separate from the secret rather than derived from it. * `api_region` — which Nash API the widget bundle should talk to, as one of the published wire tokens the widget loader accepts: `"us"` or `"au"`. Never a deployment region string like `us-west-1` — the browser resolves this against its own build-time endpoint table, not against server config (see `embed_session_service.resolve_api_region`).
  - `client_secret` string, required: Browser-held session secret (`wcs_…`). Shown once, never retrievable.
  - `expires_at` string, date-time, required
  - `session_id` string, required
  - `api_region` string, required

## Other responses

- `422`: Unprocessable Content

---

[API](https://skmtc.dev/nash/apis/nash-api.md) - [All operations](https://skmtc.dev/nash/apis/nash-api/llms.txt) - [OpenAPI document](https://skmtc.dev/nash/apis/nash-api/revisions/e3713837c5c9?raw)
