{
  "openapi": "3.0.0",
  "info": {
    "title": "AGI Workforce API",
    "version": "1.0.0",
    "description": "OpenAI-compatible inference gateway plus the billing and device-authorization endpoints the first-party apps use.\n\nThe complete API base URL is `https://agiworkforce.com/api`. The API host also exposes the OpenAI-compatible aliases `/v1/chat/completions`, `/v1/models`, `/v1/embeddings`, `/v1/audio/transcriptions`, and `/v1/credits/balance` at `https://api.agiworkforce.com`, plus `/health`. Other operations use the complete API base URL above.\n\nTwo credential types authenticate here and they are NOT interchangeable. An AGI API key (`sk_live_…`/`sk_test_…`, issued under Settings > API Keys) works only on the operations that declare `ApiKeyAuth`; every other operation needs a session bearer token. Each operation states which one it takes. Rate limits are published in `docs/standards/api-rate-limits.md`.",
    "contact": {
      "name": "AGI Workforce Support",
      "email": "contact@agiworkforce.com",
      "url": "https://agiworkforce.com"
    },
    "license": {
      "name": "MIT"
    }
  },
  "servers": [
    {
      "url": "https://agiworkforce.com/api",
      "description": "Production API server"
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Session bearer token — a Clerk session JWT or a first-party device token. Browser requests may present the session cookie instead. AGI API keys are rejected wherever this is the only accepted scheme."
      },
      "ApiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "AGI API key (`sk_live_…` / `sk_test_…`) issued under Settings > API Keys. Scopes are chosen at issue time; an operation lists the one it needs in `x-agi-api-key-scope` and answers 403 `insufficient_scope` without it."
      }
    },
    "schemas": {
      "CheckoutRequest": {
        "type": "object",
        "required": ["plan", "billingInterval"],
        "properties": {
          "plan": {
            "type": "string",
            "enum": ["basic", "pro", "max", "max_15x", "team"],
            "description": "The subscription plan to checkout"
          },
          "billingInterval": {
            "type": "string",
            "enum": ["monthly", "yearly"],
            "description": "Billing cycle interval"
          },
          "seats": {
            "type": "integer",
            "minimum": 2,
            "maximum": 999999,
            "description": "Licensed seat count. Required for per-seat plans (team) and rejected for per-account plans. Charged as the Stripe line-item quantity."
          }
        }
      },
      "DeviceLinkRequest": {
        "type": "object",
        "required": ["device_id", "device_type"],
        "properties": {
          "device_id": {
            "type": "string",
            "maxLength": 255,
            "description": "Unique device identifier"
          },
          "device_name": {
            "type": "string",
            "maxLength": 200,
            "description": "Human-readable device name"
          },
          "device_type": {
            "type": "string",
            "enum": ["desktop", "mobile", "web"],
            "description": "Type of device"
          },
          "device_fingerprint": {
            "type": "string",
            "description": "Optional device fingerprint used to prevent unauthorized polling",
            "maxLength": 255
          }
        }
      },
      "DeviceCode": {
        "type": "object",
        "required": ["link_code", "device_id", "verify_url", "expires_at"],
        "properties": {
          "link_code": {
            "type": "string",
            "description": "The code the user should approve"
          },
          "device_id": {
            "type": "string",
            "description": "Device identifier associated with this code"
          },
          "verify_url": {
            "type": "string",
            "format": "uri",
            "description": "URL where user can verify the device"
          },
          "expires_at": {
            "type": "integer",
            "description": "Unix timestamp (seconds) when code expires"
          },
          "qr_code_url": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "Optional QR code URL"
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "User ID"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "User email address"
          },
          "subscription": {
            "type": "object",
            "properties": {
              "plan_tier": {
                "type": "string",
                "enum": ["free", "basic", "pro", "max", "max_15x", "team", "enterprise"]
              },
              "status": {
                "type": "string",
                "enum": ["active", "trialing", "past_due", "canceled"]
              },
              "current_period_end": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "ApiError": {
        "type": "object",
        "description": "OpenAI-shaped error envelope returned by the inference endpoints.",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "message": { "type": "string" },
              "type": {
                "type": "string",
                "enum": ["invalid_request_error", "insufficient_quota", "api_error", "server_error"]
              },
              "code": { "type": "string", "nullable": true }
            }
          }
        }
      },
      "RateLimitError": {
        "type": "object",
        "description": "Body of a 429. `retry_after_seconds` mirrors the `Retry-After` header; see docs/standards/api-rate-limits.md for the per-endpoint ceilings.",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string", "enum": ["RATE_LIMIT_EXCEEDED"] },
              "message": { "type": "string" },
              "retry_after_seconds": { "type": "integer" },
              "reset_at": { "type": "string", "format": "date-time" }
            }
          },
          "rateLimit": {
            "type": "object",
            "properties": {
              "limit": { "type": "integer" },
              "remaining": { "type": "integer" },
              "reset": { "type": "string", "format": "date-time" },
              "reset_at": { "type": "string", "format": "date-time" },
              "retry_after_seconds": { "type": "integer" }
            }
          }
        }
      },
      "Model": {
        "type": "object",
        "description": "OpenAI-compatible model record, extended with the catalog fields a router needs.",
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string", "enum": ["model"] },
          "created": { "type": "integer" },
          "owned_by": { "type": "string", "description": "Provider that serves the model." },
          "permission": { "type": "array", "items": {} },
          "root": { "type": "string" },
          "parent": { "type": "string", "nullable": true },
          "tier": {
            "type": "string",
            "enum": ["basic", "pro", "max"],
            "description": "Lowest paid tier that may select this model."
          },
          "context_window": { "type": "integer" },
          "max_output": { "type": "integer" }
        }
      },
      "ModelList": {
        "type": "object",
        "properties": {
          "object": { "type": "string", "enum": ["list"] },
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Model" } },
          "x_agi_workforce": {
            "type": "object",
            "properties": {
              "user_tier": { "type": "string" },
              "total_available": { "type": "integer" },
              "allowed_auto_modes": { "type": "array", "items": { "type": "string" } }
            }
          }
        }
      },
      "ChatCompletionRequest": {
        "type": "object",
        "required": ["model", "messages"],
        "properties": {
          "model": {
            "type": "string",
            "description": "A model id from GET /llm/v1/models, or an auto mode from `x_agi_workforce.allowed_auto_modes`."
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["role", "content"],
              "properties": {
                "role": {
                  "type": "string",
                  "enum": ["system", "user", "assistant", "tool", "function"]
                },
                "content": {
                  "description": "A string, or the OpenAI content-part array (`text`, `image_url`, `file`).",
                  "oneOf": [
                    { "type": "string" },
                    { "type": "array", "items": { "type": "object" } }
                  ]
                },
                "name": { "type": "string" },
                "tool_calls": { "type": "array", "maxItems": 32, "items": { "type": "object" } },
                "tool_call_id": { "type": "string", "maxLength": 256 }
              }
            }
          },
          "stream": { "type": "boolean", "default": false },
          "temperature": { "type": "number", "minimum": 0, "maximum": 2 },
          "top_p": { "type": "number", "minimum": 0, "maximum": 1 },
          "n": { "type": "integer", "minimum": 1 },
          "stop": {
            "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }]
          },
          "max_tokens": { "type": "integer", "minimum": 1, "maximum": 64000 },
          "max_completion_tokens": { "type": "integer", "minimum": 1, "maximum": 64000 },
          "presence_penalty": { "type": "number", "minimum": -2, "maximum": 2 },
          "frequency_penalty": { "type": "number", "minimum": -2, "maximum": 2 },
          "logit_bias": {
            "type": "object",
            "additionalProperties": { "type": "number", "minimum": -100, "maximum": 100 }
          },
          "user": { "type": "string" },
          "tools": { "type": "array", "maxItems": 64, "items": { "type": "object" } },
          "tool_choice": { "description": "`none`, `auto`, `required`, or a named function." },
          "response_format": {
            "type": "object",
            "description": "`text` and `json_object` are honoured. `json_schema` is refused rather than ignored.",
            "properties": {
              "type": { "type": "string", "enum": ["text", "json_object"] }
            }
          }
        }
      },
      "ChatCompletionResponse": {
        "type": "object",
        "description": "OpenAI-compatible completion. When `stream` is true the response is `text/event-stream` of `chat.completion.chunk` events terminated by `data: [DONE]` instead.",
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string", "enum": ["chat.completion"] },
          "created": { "type": "integer" },
          "model": { "type": "string" },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": { "type": "integer" },
                "message": {
                  "type": "object",
                  "properties": {
                    "role": { "type": "string", "enum": ["assistant"] },
                    "content": { "type": "string", "nullable": true },
                    "tool_calls": { "type": "array", "items": { "type": "object" } }
                  }
                },
                "finish_reason": { "type": "string" }
              }
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "prompt_tokens": { "type": "integer" },
              "completion_tokens": { "type": "integer" },
              "total_tokens": { "type": "integer" },
              "cache_creation_input_tokens": { "type": "integer", "nullable": true },
              "cache_read_input_tokens": { "type": "integer", "nullable": true }
            }
          },
          "x_agi_workforce": {
            "type": "object",
            "description": "Gateway metadata: the provider that served the turn and the routing decision behind it."
          }
        }
      },
      "EmbeddingsRequest": {
        "type": "object",
        "required": ["input"],
        "properties": {
          "input": {
            "description": "One string, or a batch of at most 100, each at most 32000 characters.",
            "oneOf": [
              { "type": "string", "minLength": 1, "maxLength": 32000 },
              {
                "type": "array",
                "minItems": 1,
                "maxItems": 100,
                "items": { "type": "string", "minLength": 1, "maxLength": 32000 }
              }
            ]
          },
          "model": { "type": "string", "maxLength": 200 },
          "encoding_format": {
            "type": "string",
            "enum": ["float"],
            "description": "`base64` is rejected, not ignored — a caller expecting base64 must not receive floats."
          },
          "user": { "type": "string", "maxLength": 200 }
        }
      },
      "EmbeddingsResponse": {
        "type": "object",
        "properties": {
          "object": { "type": "string", "enum": ["list"] },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "object": { "type": "string", "enum": ["embedding"] },
                "index": { "type": "integer" },
                "embedding": { "type": "array", "items": { "type": "number" } }
              }
            }
          },
          "model": { "type": "string" },
          "usage": {
            "type": "object",
            "properties": {
              "prompt_tokens": { "type": "integer" },
              "total_tokens": { "type": "integer" }
            }
          }
        }
      },
      "CreditBalance": {
        "type": "object",
        "description": "Percentage-only managed-usage status. Ledger units and allocations never cross this boundary.",
        "properties": {
          "object": { "type": "string", "enum": ["credit_balance"] },
          "subscription": {
            "type": "object",
            "properties": {
              "plan_tier": { "type": "string" },
              "status": { "type": "string" },
              "current_period_end": { "type": "string", "format": "date-time", "nullable": true }
            }
          },
          "credits": {
            "type": "object",
            "properties": {
              "usage_percentage": { "type": "number" },
              "reset_at": { "type": "string", "format": "date-time", "nullable": true },
              "seconds_until_reset": { "type": "integer" },
              "has_usage_remaining": { "type": "boolean" }
            }
          }
        }
      },
      "ManagedUsageSummary": {
        "type": "object",
        "description": "Percentage-only managed-usage summary across every rolling window. Ledger units and allocations never cross this boundary.",
        "required": [
          "plan_tier",
          "usage_percentage",
          "usage_reset_at",
          "has_usage_remaining",
          "period_start",
          "period_end",
          "subscription_status",
          "session_usage_percentage",
          "session_reset_at",
          "weekly_usage_percentage",
          "weekly_reset_at",
          "flagship_weekly_usage_percentage",
          "flagship_weekly_reset_at"
        ],
        "properties": {
          "plan_tier": { "type": "string" },
          "subscription_status": { "type": "string" },
          "usage_percentage": { "type": "number" },
          "usage_reset_at": { "type": "string", "format": "date-time", "nullable": true },
          "has_usage_remaining": { "type": "boolean" },
          "period_start": { "type": "string", "format": "date-time", "nullable": true },
          "period_end": { "type": "string", "format": "date-time", "nullable": true },
          "session_usage_percentage": { "type": "number" },
          "session_reset_at": { "type": "string", "format": "date-time", "nullable": true },
          "weekly_usage_percentage": { "type": "number" },
          "weekly_reset_at": { "type": "string", "format": "date-time", "nullable": true },
          "flagship_weekly_usage_percentage": { "type": "number" },
          "flagship_weekly_reset_at": { "type": "string", "format": "date-time", "nullable": true },
          "credit_balance_cents": { "type": "integer", "nullable": true },
          "overage_enabled": { "type": "boolean" }
        }
      }
    }
  },
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/llm/v1/models": {
      "get": {
        "summary": "List available models",
        "description": "Models the caller may select, in OpenAI `/v1/models` shape. Callers with no `Authorization` header get the free catalog; a credential that fails to verify is rejected rather than downgraded to it, so a revoked key never looks like a lost entitlement.",
        "tags": ["Inference"],
        "security": [{ "ApiKeyAuth": [] }, { "BearerAuth": [] }, {}],
        "x-agi-api-key-scope": "models:read",
        "responses": {
          "200": {
            "description": "Model list for the caller's tier",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ModelList" } }
            }
          },
          "401": {
            "description": "Presented credential did not verify",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "403": {
            "description": "API key lacks the `models:read` scope",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/RateLimitError" } }
            }
          }
        }
      }
    },
    "/llm/v1/chat/completions": {
      "post": {
        "summary": "Create a chat completion",
        "description": "OpenAI-compatible chat completions, streaming or buffered.\n\nTakes an AGI API key or a session bearer token. A key is always pinned to the `api` client surface regardless of any `x-agi-surface` header, and that surface is gated on the `managed_api` plan capability, so a key on a plan without it answers 403 `managed_api_plan_required`.",
        "tags": ["Inference"],
        "security": [{ "ApiKeyAuth": [] }, { "BearerAuth": [] }],
        "x-agi-api-key-scope": "inference:write",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ChatCompletionRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Completion, or an SSE stream when `stream` is true",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ChatCompletionResponse" }
              },
              "text/event-stream": { "schema": { "type": "string" } }
            }
          },
          "400": {
            "description": "Invalid request body",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "401": { "description": "Not authenticated" },
          "402": {
            "description": "Managed usage exhausted",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "403": {
            "description": "API key lacks the `inference:write` scope, or the calling plan lacks the capability for the resolved client surface",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "422": {
            "description": "Refused by content policy",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/RateLimitError" } }
            }
          }
        }
      }
    },
    "/llm/v1/embeddings": {
      "post": {
        "summary": "Create embeddings",
        "description": "OpenAI-compatible embeddings. Takes a session bearer token only: the route declares no API-key scope, so a key is refused at the auth gate. `Idempotency-Key` is required so a retry settles the reservation once.",
        "tags": ["Inference"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/EmbeddingsRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "Embedding vectors, indexed to the input batch",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EmbeddingsResponse" }
              }
            }
          },
          "400": { "description": "Invalid embeddings request" },
          "401": { "description": "Not authenticated" },
          "402": {
            "description": "Managed usage exhausted",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/RateLimitError" } }
            }
          }
        }
      }
    },
    "/llm/v1/audio/transcriptions": {
      "post": {
        "summary": "Transcribe audio",
        "description": "OpenAI-compatible transcription. The upload is capped at 25 MB and its first bytes are sniffed, so a declared audio MIME type on non-audio content is rejected.",
        "tags": ["Inference"],
        "security": [{ "ApiKeyAuth": [] }, { "BearerAuth": [] }],
        "x-agi-api-key-scope": "inference:write",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": { "type": "string", "format": "binary" },
                  "model": {
                    "type": "string",
                    "description": "A live OpenAI speech-to-text model id. Anything else falls back to the default transcription model."
                  },
                  "language": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Transcription" },
          "400": {
            "description": "Missing file or unparseable form data",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "401": { "description": "Not authenticated" },
          "403": { "description": "API key lacks the `inference:write` scope" },
          "413": { "description": "Audio file exceeds 25 MB" },
          "415": { "description": "Unsupported audio type, or content that is not audio" },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/RateLimitError" } }
            }
          }
        }
      }
    },
    "/llm/v1/credits/balance": {
      "get": {
        "summary": "Get managed-usage balance",
        "description": "Percentage-only managed-usage status for the calling account, plus when it resets.",
        "tags": ["Inference"],
        "security": [{ "ApiKeyAuth": [] }, { "BearerAuth": [] }],
        "x-agi-api-key-scope": "usage:read",
        "responses": {
          "200": {
            "description": "Usage status",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/CreditBalance" } }
            }
          },
          "401": { "description": "Not authenticated" },
          "403": {
            "description": "No subscription record, or the API key lacks the `usage:read` scope",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/RateLimitError" } }
            }
          }
        }
      }
    },
    "/usage": {
      "get": {
        "summary": "Get managed-usage summary",
        "description": "Percentage-only managed-usage summary for the calling account across every rolling window, plus the subscription state those windows are measured against. Ledger units and allocations never cross this boundary.",
        "tags": ["Billing"],
        "security": [{ "ApiKeyAuth": [] }, { "BearerAuth": [] }],
        "x-agi-api-key-scope": "usage:read",
        "responses": {
          "200": {
            "description": "Usage summary",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ManagedUsageSummary" }
              }
            }
          },
          "401": { "description": "Not authenticated" },
          "403": {
            "description": "API key lacks the `usage:read` scope",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/RateLimitError" } }
            }
          }
        }
      }
    },
    "/checkout": {
      "post": {
        "summary": "Create a checkout session",
        "description": "Initiate a Stripe checkout session for subscription",
        "tags": ["Billing"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout session created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri",
                      "description": "Stripe checkout URL"
                    },
                    "sessionId": {
                      "type": "string",
                      "description": "Stripe session ID"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request parameters"
          },
          "401": {
            "description": "Not authenticated"
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/device/link": {
      "post": {
        "summary": "Generate device authorization code",
        "description": "Create a device authorization code for linking a new device",
        "tags": ["Device Authorization"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeviceLinkRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device code generated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceCode"
                }
              }
            }
          },
          "400": {
            "description": "Invalid device parameters"
          },
          "429": {
            "description": "Too many device authorization requests"
          }
        }
      }
    },
    "/device/poll": {
      "post": {
        "summary": "Poll device authorization status",
        "description": "Check if a device has been authorized by the user",
        "tags": ["Device Authorization"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["device_id"],
                "properties": {
                  "device_id": {
                    "type": "string"
                  },
                  "device_fingerprint": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device authorization status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": ["pending", "approved", "denied", "expired"]
                    },
                    "access_token": {
                      "type": "string",
                      "description": "Session token if approved"
                    },
                    "refresh_token": {
                      "type": "string",
                      "description": "Refresh token if approved"
                    },
                    "user": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "email": {
                          "type": "string",
                          "format": "email"
                        },
                        "name": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Device fingerprint mismatch"
          }
        }
      }
    },
    "/device/approve": {
      "post": {
        "summary": "Approve or deny a device authorization code",
        "description": "Approve (or deny) a device-link code so the device can retrieve a one-time session token.",
        "tags": ["Device Authorization"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["code"],
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "action": {
                    "type": "string",
                    "enum": ["approve", "deny"]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Device code processed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string",
                      "enum": ["approved", "denied"]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated"
          },
          "409": {
            "description": "Code already processed"
          }
        }
      }
    },
    "/me": {
      "get": {
        "summary": "Get current user information",
        "description": "Retrieve authenticated user's profile and subscription information",
        "tags": ["Users"],
        "responses": {
          "200": {
            "description": "User information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated"
          }
        }
      }
    }
  }
}
