{
  "openapi": "3.1.0",
  "info": {
    "title": "NanoGPT Management API",
    "version": "2026-09-05-beta",
    "summary": "Machine-to-machine NanoGPT account management",
    "description": "A separately authenticated control-plane API for declarative NanoGPT account management. Management tokens cannot be used for inference, and inference API keys cannot be used for management.",
    "license": {
      "name": "NanoGPT Terms of Service",
      "url": "https://nano-gpt.com/legal/terms-of-service"
    }
  },
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "x-stability": "beta",
  "servers": [
    {
      "url": "https://nano-gpt.com/api/management/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "managementBearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Management API keys",
      "description": "Provision and govern inference API keys owned by the management-token account."
    },
    {
      "name": "Usage",
      "description": "Read personal subscription quotas without an inference API key."
    }
  ],
  "paths": {
    "/api-keys": {
      "get": {
        "operationId": "listManagedApiKeys",
        "tags": [
          "Management API keys"
        ],
        "summary": "List inference API keys",
        "description": "Requires `api_keys:read`. Secrets are never returned from list operations.",
        "responses": {
          "200": {
            "description": "API-key collection",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "operationId": "createManagedApiKey",
        "tags": [
          "Management API keys"
        ],
        "summary": "Create an inference API key",
        "description": "Requires `api_keys:write` and an `Idempotency-Key`. The `key` secret is returned only on creation and exact idempotent replay; it is never returned by reads.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyWrite"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "API key created",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Idempotent-Replayed": {
                "description": "Present with value `true` when this response is an exact replay of an earlier successful request using the same Idempotency-Key.",
                "schema": {
                  "type": "string",
                  "enum": [
                    "true"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/api-keys/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ApiKeyId"
        }
      ],
      "get": {
        "operationId": "retrieveManagedApiKey",
        "tags": [
          "Management API keys"
        ],
        "summary": "Retrieve an inference API key",
        "description": "Requires `api_keys:read`. The secret is never returned. Expired keys remain readable with status `expired`; unknown, revoked, and cross-account identifiers produce the same `404` response.",
        "responses": {
          "200": {
            "description": "Canonical API-key metadata",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKey"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "operationId": "updateManagedApiKey",
        "tags": [
          "Management API keys"
        ],
        "summary": "Update an inference API key",
        "description": "Requires `api_keys:write`. Omitted fields are unchanged; an explicit `null` clears a nullable limit or expiration.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated canonical API-key metadata",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKey"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "operationId": "revokeManagedApiKey",
        "tags": [
          "Management API keys"
        ],
        "summary": "Revoke an inference API key",
        "description": "Requires `api_keys:write`. Revocation is terminal and idempotent; delegated OAuth child credentials are revoked with their source key.",
        "responses": {
          "204": {
            "description": "API key is revoked",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "409": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/subscription/usage": {
      "get": {
        "operationId": "getManagedSubscriptionUsage",
        "tags": [
          "Usage"
        ],
        "summary": "Read subscription usage",
        "description": "Requires usage:read explicitly; api_keys:read and api_keys:write do not grant access. Returns the token owner\u2019s personal subscription quotas. Does not return billing identifiers, cancellation metadata, or inference-key routing advice. No account selector or force-refresh parameter is accepted. This permission cannot perform inference or manage API keys.",
        "responses": {
          "200": {
            "description": "Subscription quotas; unavailable counters are null with degraded=true.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionUsage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          },
          "500": {
            "$ref": "#/components/responses/Error"
          },
          "503": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "managementBearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Dedicated NanoGPT management token beginning with `sk-nano-mgmt-`. Inference API keys are not accepted."
      }
    },
    "parameters": {
      "ApiKeyId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Stable non-secret numeric identifier returned by NanoGPT.",
        "schema": {
          "type": "string",
          "pattern": "^[1-9][0-9]*$"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Caller-generated identifier for safely replaying an identical create request. Reuse with a different body returns `409`.",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 200
        }
      }
    },
    "headers": {
      "RequestId": {
        "description": "Stable identifier for support and audit correlation.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "NullableRpdLimit": {
        "type": [
          "integer",
          "null"
        ],
        "minimum": 0,
        "maximum": 10000000
      },
      "NullableInputTokenLimit": {
        "type": [
          "integer",
          "null"
        ],
        "minimum": 0,
        "maximum": 2147483647
      },
      "NullableUsdLimit": {
        "type": [
          "number",
          "null"
        ],
        "minimum": 0,
        "maximum": 100000,
        "multipleOf": 0.0001
      },
      "ZdrPolicy": {
        "type": "string",
        "enum": [
          "zdr",
          "off",
          "unset"
        ],
        "description": "Zero Data Retention routing policy. `off` is presented as Anonymized routing. `unset` is retained only for legacy API keys."
      },
      "ExplicitZdrPolicy": {
        "type": "string",
        "enum": [
          "zdr",
          "off"
        ],
        "description": "Explicit routing policy for a newly created API key. `off` is presented as Anonymized routing."
      },
      "ApiKeyFields": {
        "type": "object",
        "required": [
          "id",
          "object",
          "name",
          "status",
          "created_at",
          "expires_at",
          "daily_rpd_limit",
          "daily_input_token_limit",
          "daily_usd_limit",
          "weekly_usd_limit",
          "monthly_usd_limit",
          "zdr_policy"
        ],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$"
          },
          "object": {
            "type": "string",
            "const": "api_key"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "expired"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "daily_rpd_limit": {
            "$ref": "#/components/schemas/NullableRpdLimit"
          },
          "daily_input_token_limit": {
            "$ref": "#/components/schemas/NullableInputTokenLimit"
          },
          "daily_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "weekly_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "monthly_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "zdr_policy": {
            "$ref": "#/components/schemas/ZdrPolicy"
          }
        }
      },
      "ApiKey": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ApiKeyFields"
          }
        ],
        "unevaluatedProperties": false
      },
      "ApiKeyCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ApiKeyFields"
          },
          {
            "type": "object",
            "required": [
              "key"
            ],
            "properties": {
              "key": {
                "type": "string",
                "readOnly": true,
                "description": "Inference secret returned on create and exact idempotent replay only. Store it securely."
              }
            }
          }
        ],
        "unevaluatedProperties": false
      },
      "ApiKeyWrite": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "pattern": ".*\\S.*"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "daily_rpd_limit": {
            "$ref": "#/components/schemas/NullableRpdLimit"
          },
          "daily_input_token_limit": {
            "$ref": "#/components/schemas/NullableInputTokenLimit"
          },
          "daily_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "weekly_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "monthly_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "zdr_policy": {
            "$ref": "#/components/schemas/ExplicitZdrPolicy"
          }
        }
      },
      "ApiKeyPatch": {
        "type": "object",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "pattern": ".*\\S.*"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "daily_rpd_limit": {
            "$ref": "#/components/schemas/NullableRpdLimit"
          },
          "daily_input_token_limit": {
            "$ref": "#/components/schemas/NullableInputTokenLimit"
          },
          "daily_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "weekly_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "monthly_usd_limit": {
            "$ref": "#/components/schemas/NullableUsdLimit"
          },
          "zdr_policy": {
            "$ref": "#/components/schemas/ZdrPolicy"
          }
        }
      },
      "ApiKeyList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiKey"
            }
          }
        }
      },
      "ErrorDetail": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "field",
          "issue"
        ],
        "properties": {
          "field": {
            "type": "string"
          },
          "issue": {
            "type": "string"
          }
        }
      },
      "ErrorBody": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "code",
              "message",
              "request_id"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string"
              },
              "details": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ErrorDetail"
                }
              }
            }
          }
        }
      },
      "UsageQuota": {
        "type": [
          "object",
          "null"
        ],
        "description": "Null when this quota is not configured or applicable. Unavailable counters are null with degraded=true. percentUsed is a fraction and may exceed 1. resetAt is UNIX epoch milliseconds.",
        "properties": {
          "used": {
            "type": [
              "number",
              "null"
            ]
          },
          "remaining": {
            "type": [
              "number",
              "null"
            ]
          },
          "percentUsed": {
            "type": [
              "number",
              "null"
            ]
          },
          "resetAt": {
            "type": [
              "number",
              "null"
            ]
          },
          "degraded": {
            "type": "boolean"
          }
        },
        "required": [
          "used",
          "remaining",
          "percentUsed",
          "resetAt"
        ],
        "additionalProperties": false
      },
      "SubscriptionUsage": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "active",
          "state",
          "limits",
          "dailyInputTokens",
          "weeklyInputTokens",
          "dailyImages",
          "period"
        ],
        "properties": {
          "active": {
            "type": "boolean"
          },
          "state": {
            "type": "string",
            "enum": [
              "active",
              "grace",
              "inactive"
            ]
          },
          "limits": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "dailyInputTokens",
              "weeklyInputTokens",
              "dailyImages"
            ],
            "properties": {
              "dailyInputTokens": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "weeklyInputTokens": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "dailyImages": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "dailyInputTokens": {
            "$ref": "#/components/schemas/UsageQuota"
          },
          "weeklyInputTokens": {
            "$ref": "#/components/schemas/UsageQuota"
          },
          "dailyImages": {
            "$ref": "#/components/schemas/UsageQuota"
          },
          "tokens": {
            "$ref": "#/components/schemas/UsageQuota"
          },
          "period": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "currentPeriodEnd"
            ],
            "properties": {
              "currentPeriodEnd": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          },
          "usageUnits": {
            "type": "string",
            "enum": [
              "tokens"
            ],
            "description": "Present for token-based trials."
          },
          "tokenLimits": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "total"
            ],
            "properties": {
              "total": {
                "type": "number"
              }
            },
            "description": "Present for token-based trials."
          }
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Management API error",
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/RequestId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorBody"
            }
          }
        }
      }
    }
  }
}
