ULTINEO

AI API keys

A key is what authenticates a call and what limits it. This resource manages your AI project's keys, including the one making the request. Only a hash of the secret is stored, so a key is shown in full exactly once, in the response that creates it.

Endpoints

MethodPathScope
GET/v1/ai/key/listkey:read
GET/v1/ai/key/detail/currentkey:read
GET/v1/ai/key/detail/<key_id>key:read
POST/v1/ai/key/createkey:write
PATCH/v1/ai/key/detail/<key_id>key:write
DELETE/v1/ai/key/detail/<key_id>key:write

<key_id> is a key identifier, prefixed papi_. current is a reserved word in that position: it stands for the key the request is made with.

The API key object

FieldTypeDescription
idstringThe key identifier, prefixed papi_.
objectstringAlways api_key.
namestringThe key's name.
key_previewstringsk-project-... followed by the last four characters of the secret, so you can recognise it.
scopearrayThe scopes the key grants. See Your first AI API call.
statusstringactivated or suspended. Only an activated key authenticates.
expires_atintegerWhen the key stops working, in Unix seconds, or null for a key that never expires.
last_used_atintegerWhen the key last authenticated a call, or null.
created_bystringThe account of your project that created the key, or an empty string when no account of your project did.
created_atintegerCreation time, in Unix seconds.
updated_atintegerLast change, in Unix seconds.

The secret itself appears in no read response. key_preview is the only part of it the API shows you again.

List the keys

GET /v1/ai/key/list returns your project's keys, newest first, without the revoked ones. It accepts limit and offset.

curl
curl https://api.ultineo.com/v1/ai/key/list \
  -H "Authorization: Bearer sk-project-YOUR_KEY"
application/json
{
  "code": 200,
  "title": "OK",
  "response": {
    "object": "list",
    "data": [
      {
        "id": "papi_4e07c1b8a35df926104c",
        "object": "api_key",
        "name": "Production backend",
        "key_preview": "sk-project-...a7e1",
        "scope": ["reasoning:*", "app:read", "usage:read"],
        "status": "activated",
        "expires_at": null,
        "last_used_at": 1789209200,
        "created_by": "cons_8e2b45a10c9df7631b4a",
        "created_at": 1788414400,
        "updated_at": 1789209200
      }
    ],
    "total": 1
  }
}

Read the calling key

GET /v1/ai/key/detail/current is the quickest way to find out what your key may do, without knowing its identifier.

curl
curl https://api.ultineo.com/v1/ai/key/detail/current \
  -H "Authorization: Bearer sk-project-YOUR_KEY"

GET /v1/ai/key/detail/<key_id> reads any key of your project the same way. A key of another project, or a revoked key, gives 404 and API key not found.

Create a key

POST /v1/ai/key/create creates a new key for the same project.

ParameterTypeRequiredDescription
namestringYesA name to recognise the key by, up to 200 characters.
scopearrayNoThe scopes to grant. Defaults to ["*"], which is refused unless your own key holds *.
expires_atintegerNoWhen the key should stop working, in Unix seconds, in the future. Omit it or send 0 for a key that never expires.
curl
curl -X POST https://api.ultineo.com/v1/ai/key/create \
  -H "Authorization: Bearer sk-project-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nightly batch",
    "scope": ["reasoning:read", "reasoning:write", "usage:read"]
  }'
application/json
{
  "code": 201,
  "title": "Created",
  "response": {
    "id": "papi_b6294fc0e178ad35c9b2",
    "object": "api_key",
    "name": "Nightly batch",
    "key_preview": "sk-project-...Lb92",
    "scope": ["reasoning:read", "reasoning:write", "usage:read"],
    "status": "activated",
    "expires_at": null,
    "last_used_at": null,
    "created_by": "cons_8e2b45a10c9df7631b4a",
    "created_at": 1789209800,
    "updated_at": 1789209800,
    "key": "sk-project-7Qd1xR0mZ8pKvT3sLb…"
  }
}

Important — key is present in this one response and nowhere else. Store it before you discard the response. A lost secret cannot be recovered, only replaced by creating another key.

A key can never grant more than the key that created it. Asking for a scope your own key does not hold is refused rather than silently trimmed.

Important — Because leaving scope out means ["*"], a key that does not itself hold * must send an explicit scope list: leaving it out is a 403, even though the parameter is optional.

CodeMessageCause
422name is required.No name was sent.
422name must be at most 200 characters.The name is too long.
400scope must be a non-empty array.scope is a string, an object or an empty list.
403Cannot create a key with wider scope than the calling key.You asked for * while your own key is narrower.
403The API key is missing the required scope: <scope>You asked for a scope your own key does not hold.
422expires_at must be in the future.The expiry date has already passed.

A scope that is not written in the scope grammar (*, <resource>:*, <resource>:read or <resource>:write) is refused with 422 and a message that recalls that grammar.

Rename, suspend or reactivate a key

PATCH /v1/ai/key/detail/<key_id> changes a key's name, its status, or both.

ParameterTypeDescription
namestringA new name, up to 200 characters.
statusstringsuspended to stop the key without deleting it, activated to bring it back.
curl
curl -X PATCH https://api.ultineo.com/v1/ai/key/detail/papi_b6294fc0e178ad35c9b2 \
  -H "Authorization: Bearer sk-project-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "suspended" }'

The answer is the updated key. A suspended key answers 403 on every AI path until you reactivate it.

CodeMessageCause
400Nothing to update: send name and/or status.Neither field was sent.
422status must be activated or suspended.status is another value.
422Cannot suspend the API key currently in use.You tried to suspend the key the request is made with.
404API key not found.The key is not one of your project's keys, or it was revoked.

Revoke a key

DELETE /v1/ai/key/detail/<key_id> revokes the key at once. Any later call made with it answers 403 and The API key doesn't have permissions to perform the request., the same answer an unknown key gets. A revoked key cannot be reactivated.

curl
curl -X DELETE https://api.ultineo.com/v1/ai/key/detail/papi_b6294fc0e178ad35c9b2 \
  -H "Authorization: Bearer sk-project-YOUR_KEY"
application/json
{
  "code": 200,
  "title": "OK",
  "response": {
    "deleted": true,
    "id": "papi_b6294fc0e178ad35c9b2"
  }
}

The key you are calling with is refused with 422 and Cannot revoke the API key currently in use., so a rotation cannot lock you out halfway. Create the new key, move your traffic onto it, then revoke the old key with the new one.