---
title: "Create a personal access token"
method: POST
path: "/pat"
tags: ["Personal access tokens"]
---

# Create a personal access token

`POST /pat`

## Request

- Base URL: `https://api.nullplatform.com`
- URL: `https://api.nullplatform.com/pat`
- Auth: HTTP bearer

Creates a personal access token that acts as you. It either follows your access (`access: same_as_user`) or holds the grants you send (`access: grants`), and every check combines it with your access at that moment, so it can never do more than you.

> ℹ️ **Note:** Personal access tokens are managed with your own login session. A request authenticated with an API key, a personal access token included, is rejected with a `403`.

## Request body

- PatNew: An expiration is required: send `expires_in` or `expires_at`, not both. Sending both returns a `400` with id `API_KEY_SERVICE.AMBIGUOUS_EXPIRATION`.
  - `name` string, required: A descriptive name for the token, for example where it runs.
  - `expires_in` integer: How long the token lives, in seconds (at least 60), counted from the server's clock when it receives the request. Send this or `expires_at`, not both. The expiration it resolves to must be at most a year away. Prefer `expires_in` over `expires_at`: because it counts from the server's clock, a lifetime at the limit isn't rejected when your own clock runs ahead. Only `expires_at` is stored and returned.
  - `expires_at` string, date-time: The ISO-8601 UTC timestamp of when the token stops working. It must be in the future and at most a year away. Send this or `expires_in`, not both.
  - `access` 'grants' | 'same_as_user': What the token can do. - `same_as_user`: the token follows your access in the organization, including roles you get or lose later. Send no `grants`. - `grants`: the token holds only the `grants` you send. Either way, every check combines the token's access with yours at that moment.
  - `grants` union[]: Required when `access` is `grants`, and not allowed with `same_as_user`. Every item carries an `nrn` plus one of the shapes an API key grant takes: `role_id` or `role_slug`, `actions`, or `inherits` with `actions.add` and `actions.remove`. > ℹ️ **Note:** You can only grant roles you hold on that resource or one above it, and actions you hold there.
    - union
      - object
        - `nrn` string, required: The NRN of the resource where the API key's role is assigned.
        - `role_slug` string, required: The slug of the role assigned to the API key for this NRN. > Note: See [Roles](/docs/authorization/roles) for more info. >
      - object
        - `nrn` string, required: The NRN of the resource where the API key's role is assigned.
        - `role_id` integer, required: The ID of the role assigned to the API key for this NRN. > Note: See [Roles](/docs/authorization/roles) for more info. >
      - object
        - `nrn` string, required: The NRN of the resource the grant applies to.
        - `actions` string[], required: The actions the API key may call at this NRN, without naming an existing role. nullplatform creates a role private to the key carrying exactly these actions. > Note: You can only grant actions you could hand out at that NRN yourself: the ones > you hold there, plus the ones carried by roles you may assign to an API key there. >
      - object
        - `nrn` string, required: The NRN of the resource the grant applies to.
        - `inherits` union[], required: Existing roles, by slug or ID, merged into a single role private to this key. Inheriting two roles in one grant is not the same as granting them separately: it produces one role, which `actions.add` and `actions.remove` can then adjust. You must be allowed to assign each inherited role to an API key at this NRN, the same check a grant by `role_id` passes. The key follows the roles it inherits: an action later added to one of them reaches the key too. > Note: A role private to another API key cannot be inherited. >
          - union
            - string
            - integer
        - `actions` object: How the union of the inherited roles is adjusted.
          - `add` string[]: Actions granted on top of what the inherited roles provide. Measured against what you can hand out at this NRN.
          - `remove` string[]: Inherited actions excluded from this grant. Each must be carried by one of the inherited roles, and none may also be in `add`.
  - `tags` object[]: Tags to find the token by. Each key can appear only once.
    - `key` string: Tag key.
    - `value` string: Tag value.

## Response `201`

The operation was successful.

- PatPostResponse
  - `id` integer, required: Unique ID for the token.
  - `name` string, required: The descriptive name given to the token.
  - `masked_api_key` string: The token, masked.
  - `access` 'grants' | 'same_as_user', required: Whether the token follows your access (`same_as_user`) or holds its own grants (`grants`).
  - `tags` object[], required: Tags associated with the token. Empty when it has none.
    - `key` string, required: Tag key.
    - `value` string, required: Tag value.
  - `grants` object[], required: What the token can do. For a `same_as_user` token, these are your own grants in the organization at the moment of the request. A token that no longer works, because it expired or your user is inactive, reports none.
    - `id` integer: The ID of the grant.
    - `nrn` string: The NRN of the resource the grant applies to.
    - `role_id` integer: The ID of the role granted.
    - `role_slug` string: The slug of the role granted.
    - `actions` string[]: The action names the grant resolves to, present when it was created from `actions` or `inherits`.
  - `personal` boolean: Always `true` for a personal access token.
  - `owner_id` integer: The ID of the user who created the token.
  - `acting_user_id` integer: The ID of the user the token acts as: you.
  - `last_used_at` string, date-time, nullable: The ISO-8601 UTC timestamp of when the token was last exchanged for an access token.
  - `expires_at` string, date-time, required: The ISO-8601 UTC timestamp of when the token stops working.
  - `expired` boolean: Whether the token has expired.
  - `created_at` string, date-time, required: The ISO-8601 UTC timestamp of when the token was created.
  - `updated_at` string, date-time, required: The ISO-8601 UTC timestamp of when the token was last updated.
  - `api_key` string, required: Your new personal access token. > > ⚠️ **Save your token securely.** > > The token is displayed only once. Make sure to store it in a secure location as it cannot be retrieved later.

## Other responses

- `4XX`: The request couldn't be processed. For example, a parameter is invalid, the resource doesn't exist, or you don't have permission. The body is a problem details object (RFC 9457).
- `5XX`: Something went wrong on nullplatform's side. The body is a problem details object (RFC 9457).

## Changes

- **2026-10-22** `3d300f7f8452`: 2 info
  - added the new optional request property `expires_in`
  - the request property `expires_at` became optional
- **2026-10-15** `728d4df70ca1`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/nullplatform/apis/nullplatform-api/changes/pat/post.md)

---

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