---
title: "Mint Retrieval Token User"
method: POST
path: "/api/v1/sessions/token/user"
tags: ["Sessions"]
---

# Mint Retrieval Token User

`POST /api/v1/sessions/token/user`

## Request

- Base URL: `https://api.gemina.co` (the document declares no server; this is the origin it was published from)
- URL: `https://api.gemina.co/api/v1/sessions/token/user`
- Auth: one of:
  - OAuth 2 (password, token URL `token`)
  - API key in header `X-API-Key`

Browser-safe variant of ``POST /v1/sessions/token`` for logged-in users.

Authenticates with the caller's JWT (``Authorization: Bearer <jwt>``)
and treats the ``X-API-Key`` header as the *UUID id* of one of the
user's API keys — NOT the raw secret. Ownership is verified server-side
(``APIKeyModel.id == header AND user_id == jwt``), so the raw secret
never leaves the server. Mirrors ``POST /v1/filetag/user``. Deliberately,
the key's IP allowlist is NOT enforced on this path: the console runs
from arbitrary user IPs, and JWT auth + server-side ownership is the
control — the same accepted convention as ``/v1/filetag/user``.

The minted token is identical to the server-to-server variant: signed,
query-only, TTL-clamped, tenant pinned from the key.

## Request body

- SessionTokenInDTO
  - `endUserId` string, nullable: Optional end-user scope: the token will only see documents tagged to this end-user. Omit for an admin (whole-account) session.
  - `ttlSeconds` integer, nullable: Requested TTL; clamped server-side to [300, 900] seconds.
  - `extractionIds` string[], nullable: Optional extraction scope: the minted token may only read/verify these document-extraction ids (carried in the signed `xids` claim). Omit for the existing tenant / end-user scoping. Capped at 10; an empty list is rejected rather than silently minting a tenant-wide token.

## Response `200`

Successful Response

- SessionTokenOutDTO
  - `servedAt` string, date-time
  - `servedAtTimestamp` number
  - `createdAt` string, date-time, nullable
  - `createdAtTimestamp` number, nullable
  - `token` string, required
  - `tokenType` string
  - `expiresIn` integer, required
  - `expiresAt` string, date-time, required

## Other responses

- `422`: Validation Error
- `429`: Rate or quota limit exceeded; `errors[0].error_code` says which. Retryable limits (`FILETAG_RATE_LIMIT_EXCEEDED`, burst limits) send a `Retry-After` header: back off and retry after it. `CREDIT_EXHAUSTED` for an account with no active subscription or trial sends no `Retry-After` and is not resolved by waiting: start the free trial (once per account) or choose a plan in the console.

---

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