Graine AI

Mint an API key

Mint a new API key for this organization.

Mint a new API key for this organization.

The secret is shown exactly once. Store it when you receive it; there is no endpoint that can show it again.

Requires the keys:write scope, which DENIES BY DEFAULT and is the one scope a pre-scopes key does NOT hold implicitly — no key already in circulation can mint another one until an account admin grants it.

The new key is always bound to the calling key's own organization, and may sit on the calling key's plan or a lower one but never a higher one.

Scopes. Omit scopes and the new key inherits everything the calling key holds, minus key management. Send an explicit list to mint a narrower key; send [] to mint one that can do nothing. You can never grant a scope you do not hold — that is a 403, not a silently trimmed list. Every key minted here carries an explicit scope list even when the calling key does not, so the grandfather clause stops with this key rather than propagating. GET /v2/scopes lists what is available.

The whole read-modify-write of the key store runs under a per-organization lock, so two creates issued at the same moment both survive rather than one silently overwriting the other.

Errors: 400, 401, 403 (missing scope, wrong organization, a scope the calling key does not hold, or a plan above the minting key's), 409 (another key change is in flight, or the organization is at its active-key ceiling), 422, 429, 503.

Rate limit: 1000 requests per minute per organization (bucket default). Exceeding it returns 429 with Retry-After; the X-RateLimit-* response headers report your remaining allowance on every call.

POST
/v2/api-keys
/v2/api-keys

The Authorization access token

Authorization

Authorization
Required
Bearer <token>

Your Graine API key. Create one in the dashboard under Developers, or via POST /v2/api-keys. Send it as Authorization: Bearer <key>.

In: header

Request Body

application/jsonRequired

name
Required
Name

Human label for the key, stored as the developer name.

Minimum length: 1Maximum length: 100

emailEmail | null

Contact address for the key's owner.

Format: "email"

descriptionDescription | null

Free-text note.

Maximum length: 500

planPlan | null

Plan for the new key. Defaults to the minting key's plan and may never exceed it.

Maximum length: 40

grant_api_keys_writeGrant Api Keys Write

Grant the new key key-management rights so it can mint and revoke keys itself. Off by default: the scope is otherwise stripped from the inherited permissions.

Default: false

scopesScopes | null

Scopes for the new key. Omit to inherit everything the minting key holds (minus key management). Send an explicit list to mint a narrower key; an empty list mints a key that can do nothing. You can never grant a scope you do not hold yourself. See GET /v2/scopes.

Query Parameters

organization_idOrganization Id

Optional; must match the key's organization.

Response Body

201

The new key. The secret is present in this response and nowhere else.

key_id
Required
Key Id

Stable id. Pass this to DELETE /v2/api-keys/{key_id}.

api_key
Required
Api Key

The secret. Shown exactly once — store it now.

key_preview
Required
Key Preview

Masked form of the key, safe to store and display.

developer_id
Required
Developer Id

Developer record created for this key.

developer_name
Required
Developer Name

The label you sent as name.

plan
Required
Plan

Plan the new key holds. Never higher than the minting key's.

rate_limit_tier
Required
Rate Limit Tier

Tier the new key's request ceilings are drawn from.

org_id
Required
Org Id

The organization the new key belongs to.

created_at
Required
Created At

When the key was minted.

message
Required
Message

A reminder that the secret is shown exactly once.

401

1100 — missing, unknown or inactive API key. 1101 — a browser session token was presented instead of an API key.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

403

1102 — the key is valid but lacks the scope this endpoint requires, or names another organization. GET /v2/scopes reports what a key holds.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

409

1201 — the resource's current state does not allow this action.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

422

1001 — the body or query failed validation; the message names the first offending field.

error
Required
integer

Stable integer code from the error table. Branch on this, not on the message.

message
Required
string

One human-readable sentence. Wording may change; the code will not.

429

1300 — the per-organization request rate or concurrent-call limit was reached. Carries Retry-After.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

503

1501 — a service this endpoint depends on is unreachable or returned a 5xx.

error
Required
Error

Stable integer code from the /v2 error table. Branch on this.

message
Required
Message

One human-readable sentence. Wording may change; the code will not.

curl -X POST "https://api.graine.ai/v2/api-keys?organization_id=string" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production integration",
    "email": "api-team@example.com",
    "description": "Server-side integration for the booking app.",
    "plan": "growth",
    "grant_api_keys_write": false,
    "scopes": [
      "agents:read",
      "calls:read",
      "calls:write"
    ]
  }'

The new key. The secret is present in this response and nowhere else.

{
  "key_id": "key_1a2b3c4d5e6f7890",
  "api_key": "gat_exampleKeyDoNotUse_zJ8pQ2mXv4Ld7Rt0Ng6Yc1",
  "key_preview": "gat_exampleK...6Yc1",
  "developer_id": "dev_1a2b3c4d5e6f7a8b",
  "developer_name": "Production integration",
  "plan": "growth",
  "rate_limit_tier": "growth",
  "org_id": "organization-live-EXAMPLE",
  "created_at": "2026-08-20T13:06:01.724Z",
  "message": "Save this key now - it will not be shown again."
}