---
title: "Mint a grant key against a grant (owner-only)"
method: POST
path: "/projects/v1/{project_id}/grants/{grant_id}/keys"
tags: ["Org"]
---

# Mint a grant key against a grant (owner-only)

`POST /projects/v1/{project_id}/grants/{grant_id}/keys`

## Request

- Base URL: `https://api.run402.com`
- URL: `https://api.run402.com/projects/v1/{project_id}/grants/{grant_id}/keys`
- Auth: API key in header `SIGN-IN-WITH-X`

Owner-only. Mints a credential against exactly this grant for its agent/ci principal, NARROWED by `scope`/`spend_cap`/`expires_at` — never widened. A grant key is never an owner. For `kind: run402_agent_key` the `key.token` (the bearer to hand the agent) is returned ONCE. A grant may hold several keys. Takes the `grant_key.issue` step-up for a sign-in session. Audited.

## Path parameters

- `project_id` string, required
- `grant_id` string, uuid, required

## Headers

- `SIGN-IN-WITH-X` string, required

## Request body

- GrantKeyRequest: A grant key: a credential minted against exactly one grant, narrower than it (scope, spend cap, expiry), revocable on its own, never an owner.
  - `kind` 'tempo_access_key' | 'base_disposable_eoa' | 'run402_agent_key' | 'ci_oidc': Defaults to run402_agent_key (the bearer an agent holds). erc7710 is forward-declared and rejected (501).
  - `scope` object: Defaults to the grant's own capability. Always a subset of the grant: a key never widens it.
    - `v` 1, required
    - `capabilities` string[], required
    - `projects` string[]
  - `spend_cap` object, nullable: Required for payment rails (tempo/base). usd_micros.
    - `v` 1
    - `currency` 'usd_micros'
    - `period` 'day' | 'week' | 'month'
    - `per_period` integer
    - `per_tx` integer
  - `expires_at` string, date-time, nullable
  - `public_subject` string

## Response `201`

Grant key minted

- object
  - `status` string
  - `grant_id` string, uuid
  - `key` MintedGrantKey: The minted key. `token` is the run402_agent_key bearer, returned ONCE; null for kinds that carry no bearer.
    - `key_id` string, uuid
    - `kind` string
    - `token` string, nullable: run402_agent_key bearer — returned once.
    - `expires_at` string, date-time, nullable

## Other responses

- `400`: Invalid key request (VALIDATION_FAILED, INVALID_GRANT_KEY_SCOPE, SCOPE_EXCEEDS_GRANT, SPEND_CAP_REQUIRED, INVALID_GRANT_KEY_SUBJECT)
- `403`: Owner role required (FORBIDDEN)
- `404`: No such grant on this project (GRANT_NOT_FOUND)
- `409`: The grant is revoked or expired (GRANT_REVOKED, GRANT_EXPIRED)

---

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