---
title: "Create API Key"
method: POST
path: "/service-accounts/{id}/api-keys"
tags: ["service-accounts"]
---

# Create API Key

`POST /service-accounts/{id}/api-keys`

## Request

- Base URL: `https://api.instruxi.dev/api/v1/enforcer`
- URL: `https://api.instruxi.dev/api/v1/enforcer/service-accounts/{id}/api-keys`
- Auth: one of:
  - API key in header `Authorization`
  - API key in header `X-API-Key`

Mints an env3_ key OWNED BY the service account, created_by the caller. The plaintext appears in this response only. scope is capped at the caller's own credential scope (403 insufficient_scope otherwise), same ceiling rule POST /api-keys applies to a self-minted key.

## Path parameters

- `id` string, required

## Request body

- InternalDeliveryHttpHandlerCreateAPIKeyRequest
  - `expires_at` string, date-time
  - `name` string
  - `scope` string

## Response `201`

Created

- InternalDeliveryHttpHandlerServiceAccountKeyCreatedResponse
  - `data` InternalDeliveryHttpHandlerServiceAccountKeyCreated
    - `api_key` EnforcerV3InternalDomainApikeyAPIKey
      - `account_id` string
      - `active` boolean
      - `created_at` string
      - `created_by` string: CreatedBy is the account that minted the key: provenance, never authority. Equal to AccountID for a self-minted key; nil for keys minted before 000111.
      - `expires_at` string: ExpiresAt is when the key stops authenticating (000111). nil — every key minted before the column existed — never expires. Both transports refuse an expired key through Expired, so the rule cannot differ between them.
      - `id` string
      - `key_prefix` string
      - `last_used_at` string
      - `name` string
      - `scope` string: Scope narrows what the key may do below its owner's grant. nil is the only value existing keys carry and means unnarrowed — the key acts with the account's full permissions, exactly as before the column existed. Omitted from JSON when nil, so a response for an unscoped key is byte-identical to what it was.
      - `tenant_id` string
      - `updated_at` string
    - `key` string
  - `success` boolean

## Other responses

- `400`: invalid_scope | invalid_expires_at
- `401`: Unauthorized
- `403`: insufficient_scope | agent_cannot_mint
- `404`: Not Found

---

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