VitrinaAPI

Personal tokens

The credential a member mints for themselves: it sees exactly what that person sees, and stops working when that person loses access.

Beta
This may change at any time, with a changelog entry and a notice to recent callers — see versioning.

Download the full API pública projection: openapi.json.

Issue a personal token explains this resource in prose, with runnable examples.

MethodPathWhat it does
GET/personal-tokensList personal tokens
POST/personal-tokensMint a personal token (returns the plaintext secret once)
DELETE/personal-tokens/{id}Revoke a personal token

GET /personal-tokens

List personal tokens

Your own personal tokens in this workspace, newest first. Needs personal_tokens:read, which every built-in role carries. Pass user_id to read another member’s — that additionally needs api_keys:read, the same permission that lists the workspace’s API keys.

Revoked tokens are left out unless you ask for them with include_revoked=true; EXPIRED ones are always listed, because "it expired eight days ago" is the answer to "why did my script stop". The plaintext secret is never returned — only prefix, its first characters, for telling tokens apart.

A connected app’s access tokens are not listed here: they belong to the grant that issued them and are managed with it.

ParameterInTypeRequiredConstraints
user_idqueryuuidno
include_revokedquerytrue \falseno
curl https://api.vitrinadev.com/api/v1/personal-tokens \
  -H "Authorization: Bearer $VITRINA_KEY"

Example response (200)

{
  "data": [
    {
      "id": "c2c2c2c2-0000-4000-8000-000000000001",
      "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
      "user_id": "11111111-0000-4000-8000-000000000001",
      "name": "Reportes semanales",
      "prefix": "sk_7Qm4T",
      "scopes": [
        "leads:read",
        "contacts:read"
      ],
      "created_at": "2026-09-21T13:40:02.118Z",
      "last_used_at": "2026-09-22T09:15:44.301Z",
      "expires_at": "2026-12-20T13:40:02.118Z",
      "revoked_at": null,
      "connector": false
    }
  ]
}

Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429

POST /personal-tokens

Mint a personal token (returns the plaintext secret once)

Mints a token that ACTS AS YOU. It is bound to your membership in this workspace: its effective permissions are the scopes below ∩ the ones your role holds at the moment of each request, and it reads exactly the records and sucursales you read. Narrow your role and every token acting as you narrows with it; lose the membership and the token stops working on the next request.

Omit scopes to take everything your role has right now, which is what the dialog offers. A scope you do not hold is a 403 naming it, never a silent drop. expires_at is 90 days from now when you leave it out; send null for a token with no expiry.

This is the credential to use for your own scripts. An API key (POST /api-keys) is the workspace’s and survives you; a personal token is yours and does not.

Needs personal_tokens:write, which every built-in role carries — and a SIGNED-IN SESSION: a credential cannot mint its own successor.

The plaintext secret is in the 201 body and is never retrievable again.

Body

FieldTypeRequiredConstraints
namestringyesmín. 1, máx. 120
scopesai_agents:read \ai_agents:write \ai_agents:simulate \
expires_atstring | null—date-time
curl -X POST https://api.vitrinadev.com/api/v1/personal-tokens \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Reportes semanales",
    "scopes": [
      "leads:read",
      "contacts:read"
    ],
    "expires_at": "2026-12-20T13:40:02.118Z"
  }'

Example response (201)

{
  "data": {
    "id": "c2c2c2c2-0000-4000-8000-000000000001",
    "tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
    "user_id": "11111111-0000-4000-8000-000000000001",
    "name": "Reportes semanales",
    "prefix": "sk_7Qm4T",
    "scopes": [
      "leads:read",
      "contacts:read"
    ],
    "created_at": "2026-09-21T13:40:02.118Z",
    "last_used_at": null,
    "expires_at": "2026-12-20T13:40:02.118Z",
    "revoked_at": null,
    "connector": false,
    "secret": "sk_7Qm4T…"
  }
}

Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429

DELETE /personal-tokens/{id}

Revoke a personal token

Immediate and irreversible: every request bearing this token’s secret 401s from this point on. There is no un-revoke — mint a new token instead.

Needs personal_tokens:write. Your own, always; another member’s additionally needs api_keys:write. A token that does not exist, belongs to another workspace, is an API key, or is a connected app’s access token is a 404 alike — this route is not a probe for credentials it may not revoke.

ParameterInTypeRequiredConstraints
idpathuuidyes
curl -X DELETE https://api.vitrinadev.com/api/v1/personal-tokens/<id> \
  -H "Authorization: Bearer $VITRINA_KEY"

Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429

On this page