{
  "openapi": "3.1.0",
  "info": {
    "title": "LayerBrick Core API",
    "version": "0.1.0",
    "summary": "Identity, organizations, billing, KYC, and the ALBOS agent for the LayerBrick ecosystem.",
    "description": "Core is the identity/SSO/billing hub shared by every LayerBrick brand (Comphive, TLDName, NetDNS, DakRelay, Web-Ons, Evallot). Brands never touch Core's database directly — they forward the caller's bearer token to `GET /v1/auth/me` and authorize locally from the identity it returns. This spec covers every registered Core route (auth, MFA, profile, organizations & membership, billing/invoices/payments/proformas, KYC, distributor tenancy, AI tokens, API keys, ALBOS, agent memory, knowledge base, and the staff control tower) — nothing here is aspirational or mocked. Endpoints still pending real upstream integration (outbound email, social login) are marked in their description, not hidden. API-parity doctrine: anything an operator or customer can do through a panel, this API can do too — as other brands come online, this is the contract they build against.",
    "contact": {
      "name": "LayerBrick",
      "url": "https://albos.tr/developers.html"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://albos.tr",
      "description": "Core, mounted at the apex domain"
    },
    {
      "url": "https://{brand}.albos.tr/core-api",
      "description": "Core, proxied same-origin on every brand subdomain",
      "variables": {
        "brand": {
          "default": "comphive",
          "enum": [
            "comphive",
            "tldname",
            "netdns",
            "dakrelay",
            "webons"
          ]
        }
      }
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Auth",
      "description": "Passwordless login, sessions, and the SSO identity endpoint every brand calls."
    },
    {
      "name": "Organizations",
      "description": "Orgs, membership, and role-based access."
    },
    {
      "name": "Wallet & Tokens",
      "description": "Per-org wallet ledger (bank-transfer credits) and the AI-token economy."
    },
    {
      "name": "KYC",
      "description": "Identity verification submissions and staff review."
    },
    {
      "name": "Profile & Memory",
      "description": "Detailed personal profile and the ALBOS agent-memory system (soul.md / memory.md)."
    },
    {
      "name": "ALBOS",
      "description": "The ecosystem agent — tiered autonomy over live account data."
    },
    {
      "name": "API Keys",
      "description": "Org-scoped lb_live_ keys for programmatic access — the same identity model as browser sessions."
    },
    {
      "name": "Admin",
      "description": "Staff-only control tower."
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Either a session token (from POST /v1/auth/verify) or an org-scoped API key (`lb_live_...` from POST /v1/organizations/{id}/api-keys). Both resolve to an identity via the same `requireAuth` path; API keys carry exactly one synthetic org membership and are never staff."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      },
      "Membership": {
        "type": "object",
        "properties": {
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "manager",
              "finance",
              "developer",
              "visitor"
            ]
          }
        }
      },
      "Identity": {
        "type": "object",
        "description": "Returned by GET /v1/auth/me — the SSO contract every brand relies on.",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "staff": {
            "type": "boolean"
          },
          "memberships": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Membership"
            }
          }
        }
      },
      "Organization": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "legal_type": {
            "type": "string",
            "enum": [
              "individual",
              "corporate"
            ]
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2"
          },
          "distributor_entity_id": {
            "type": "string",
            "format": "uuid"
          },
          "distributor_entity": {
            "type": "string"
          },
          "kyc_status": {
            "type": "string",
            "enum": [
              "unverified",
              "pending",
              "verified",
              "rejected"
            ]
          },
          "kyc_tier": {
            "type": "integer"
          }
        }
      },
      "Session": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "ip": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "current": {
            "type": "boolean"
          }
        }
      },
      "Member": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "manager",
              "finance",
              "developer",
              "visitor"
            ]
          }
        }
      },
      "WalletTransaction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "delta_minor": {
            "type": "integer"
          },
          "kind": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Profile": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "job_title": {
            "type": "string"
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone name, e.g. Europe/Istanbul"
          },
          "locale": {
            "type": "string",
            "enum": [
              "en",
              "tr"
            ]
          },
          "bio": {
            "type": "string"
          }
        }
      },
      "AuditEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "actor_user_id": {
            "type": "string",
            "nullable": true
          },
          "action": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "detail": {
            "type": "object"
          },
          "ip": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MemoryDoc": {
        "type": "object",
        "properties": {
          "soul_md": {
            "type": "string",
            "description": "User-authored identity/preferences document, edited by the user, read by ALBOS."
          },
          "memory_md": {
            "type": "string",
            "description": "Agent-curated activity log — an AI-written summary of your activity and ALBOS conversations when a provider is available, an honest rule-based count otherwise."
          },
          "last_curated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "curation_count": {
            "type": "integer"
          }
        }
      },
      "KYCSubmission": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "fields": {
            "type": "object",
            "description": "individual: full_name, national_id. corporate: company_name, tax_id."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected",
              "more_info_requested"
            ]
          },
          "review_notes": {
            "type": "string"
          },
          "reviewed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "requested_fields": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Populated on a more_info_requested decision — which field keys the customer needs to correct"
          },
          "purged_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Set once the minimization sweep has redacted this submission's raw payload (180 days after decision) — only status/notes/timestamps survive for audit"
          }
        }
      },
      "AlbosReply": {
        "type": "object",
        "properties": {
          "reply": {
            "type": "string"
          },
          "engine": {
            "type": "string",
            "example": "albos-v1-nvidia"
          },
          "notice": {
            "type": "string"
          },
          "tier": {
            "type": "string",
            "enum": [
              "full_or_logged_autonomy",
              "confirmation_required"
            ]
          },
          "confirmation_id": {
            "type": "string",
            "format": "uuid",
            "description": "Present only when tier is confirmation_required — pass this to POST /v1/albos/confirm to execute."
          },
          "action_summary": {
            "type": "string",
            "description": "Human-readable summary of a staged confirmation-required action (org names resolved), shown on the Approve/Cancel card. Present only with confirmation_id."
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "manager",
              "finance",
              "developer",
              "visitor"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "revoked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Invoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "number": {
            "type": "string",
            "description": "LB-<year>-NNNNNN for invoices, PF-<year>-NNNNNN for proformas"
          },
          "kind": {
            "type": "string",
            "enum": [
              "invoice",
              "proforma"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "issued",
              "partially_paid",
              "paid",
              "void"
            ]
          },
          "currency": {
            "type": "string",
            "enum": [
              "TRY",
              "EUR",
              "USD"
            ]
          },
          "total_minor": {
            "type": "integer",
            "format": "int64"
          },
          "paid_minor": {
            "type": "integer",
            "format": "int64",
            "description": "Cumulative payments applied — status derives from this, not a manual flip"
          },
          "subtotal_minor": {
            "type": "integer",
            "format": "int64"
          },
          "tax_minor": {
            "type": "integer",
            "format": "int64",
            "description": "Always 0 today (bank-transfer doctrine; VAT wiring per entity is future work)"
          },
          "issued_at": {
            "type": "string",
            "format": "date-time"
          },
          "due_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "paid_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "legal_document_url": {
            "type": "string",
            "format": "uri",
            "nullable": true,
            "description": "The actual externally-issued legal invoice (e.g. e-Fatura), when staff have attached one. The HTML render at .../html is a preview only, never a substitute for this."
          }
        }
      },
      "InvoiceLine": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string"
          },
          "brand": {
            "type": "string"
          },
          "qty": {
            "type": "integer"
          },
          "unit_minor": {
            "type": "integer",
            "format": "int64"
          },
          "amount_minor": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "Payment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "invoice_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Null for an unallocated payment (logged, not yet applied to a specific invoice)"
          },
          "invoice_number": {
            "type": "string",
            "nullable": true
          },
          "amount_minor": {
            "type": "integer",
            "format": "int64"
          },
          "currency": {
            "type": "string",
            "enum": [
              "TRY",
              "EUR",
              "USD"
            ]
          },
          "method": {
            "type": "string",
            "enum": [
              "bank_transfer",
              "manual",
              "other"
            ]
          },
          "reference": {
            "type": "string",
            "description": "Bank reference / transfer note"
          },
          "received_at": {
            "type": "string",
            "format": "date"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "Charge": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "description": {
            "type": "string"
          },
          "brand": {
            "type": "string"
          },
          "amount_minor": {
            "type": "integer",
            "format": "int64"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "invoiced",
              "quoted",
              "waived"
            ],
            "description": "quoted = pulled into a proforma without finalizing (reversible); invoiced = finalized on a real invoice"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OrganizationDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Organization"
          },
          {
            "type": "object",
            "properties": {
              "your_role": {
                "type": "string",
                "enum": [
                  "owner",
                  "manager",
                  "finance",
                  "developer",
                  "visitor"
                ]
              },
              "status": {
                "type": "string",
                "enum": [
                  "active",
                  "suspended"
                ]
              },
              "members": {
                "type": "integer"
              },
              "assets": {
                "type": "integer"
              },
              "wallet_currency": {
                "type": "string",
                "nullable": true
              },
              "wallet_balance_minor": {
                "type": "integer",
                "format": "int64",
                "nullable": true
              },
              "tokens": {
                "type": "integer",
                "format": "int64"
              },
              "legal_name": {
                "type": "string"
              },
              "tax_id": {
                "type": "string"
              },
              "registration_number": {
                "type": "string"
              },
              "registered_address": {
                "type": "object",
                "description": "{line1,line2,city,region,postal_code,country} once KYC-verified"
              },
              "kyc_locked": {
                "type": "boolean"
              },
              "kyc_verified_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "kyc_retention_until": {
                "type": "string",
                "format": "date",
                "nullable": true,
                "description": "Informational bookkeeping-retention deadline (verified_at + 10y)"
              }
            }
          }
        ]
      },
      "MemberDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Member"
          },
          {
            "type": "object",
            "properties": {
              "ai_enabled": {
                "type": "boolean",
                "description": "Whether this member may use ALBOS in this org at all"
              },
              "token_limit": {
                "type": "integer",
                "format": "int64",
                "nullable": true,
                "description": "Personal cap on tokens this member may spend; null = no personal cap (still bounded by the org's own balance)"
              },
              "tokens_spent": {
                "type": "integer",
                "format": "int64",
                "description": "Live cumulative spend attributed to this member"
              }
            }
          }
        ]
      },
      "Distributor": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 — immutable after creation; organizations route to a distributor by country"
          },
          "legal_name": {
            "type": "string"
          },
          "tax_id": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "bank_name": {
            "type": "string"
          },
          "bank_iban": {
            "type": "string"
          },
          "bank_swift": {
            "type": "string"
          },
          "contact_email": {
            "type": "string",
            "format": "email"
          },
          "contact_phone": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "profit_pct": {
            "type": "number",
            "description": "This entity's share of collected (paid) invoice totals"
          }
        }
      },
      "DistributorStaffMember": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "string",
            "enum": [
              "observer"
            ]
          },
          "since": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "KBCategory": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "article_count": {
            "type": "integer"
          }
        }
      },
      "KBArticle": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "body_md": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published"
            ]
          },
          "category": {
            "type": "string",
            "nullable": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "MFAStatus": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "enabled_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Invite": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "string",
            "enum": [
              "manager",
              "finance",
              "developer",
              "visitor"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "accepted",
              "revoked",
              "expired"
            ]
          },
          "accept_url": {
            "type": "string",
            "format": "uri",
            "description": "Present on creation only, while outbound email is not yet wired"
          }
        }
      },
      "OrgAsset": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "kind": {
            "type": "string",
            "enum": [
              "document",
              "logo",
              "link",
              "other"
            ]
          },
          "name": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "AlbosConversation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "summary": {
            "type": "string",
            "description": "≤150-word AI-written summary generated when the conversation closed"
          },
          "closed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PlatformProposal": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "problem": {
            "type": "string"
          },
          "proposal": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "accepted",
              "rejected",
              "done"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaymentClaim": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "org_name": {
            "type": "string",
            "description": "Present on the admin queue listing only"
          },
          "invoice_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "amount_minor": {
            "type": "integer",
            "format": "int64"
          },
          "currency": {
            "type": "string",
            "enum": [
              "TRY",
              "EUR",
              "USD"
            ]
          },
          "reference": {
            "type": "string",
            "description": "Bank reference the customer provided — staff verify this against the real transfer before approving"
          },
          "note": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "rejected"
            ]
          },
          "review_notes": {
            "type": "string",
            "description": "Set on rejection — visible to the customer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "reviewed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Project": {
        "type": "object",
        "description": "A Core-level concept shared by every brand — brands never own their own project table, they validate a project_id by calling GET /v1/projects/{id} server-to-server (forwarding the caller's bearer token, same pattern as session verification) and store project_id as a bare uuid locally, exactly like org_id.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "org_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  },
  "paths": {
    "/healthz": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Health check",
        "security": [],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/v1/auth/request-link": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Request a magic login link",
        "security": [],
        "description": "Upserts a user by email and issues a single-use, 15-minute magic link token. No outbound email provider is wired up yet, so the token is logged server-side; on the playground only (`DEV_ECHO_MAGIC_LINK=true`), it is also echoed in the response as `dev_token`. Rate-limited to 5/hr per email and 20/hr per IP, with an identical response either way so the limiter can't be used to probe for existing accounts.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Link issued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "dev_token": {
                      "type": "string",
                      "description": "Playground only"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/verify": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Exchange a magic link token for a session",
        "security": [],
        "description": "Single-use, expiry-enforced, row-locked against concurrent redemption. Rate-limited 15/min/IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session issued (30-day TTL)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session_token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid, expired, or already-used token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Get caller identity — the SSO endpoint every brand calls",
        "description": "Brands never touch Core's session storage directly; they forward the caller's bearer token here and authorize locally from the response.",
        "responses": {
          "200": {
            "description": "Identity",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Identity"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "Update display name",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          }
        }
      }
    },
    "/v1/auth/logout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Revoke the current session",
        "responses": {
          "200": {
            "description": "Logged out"
          }
        }
      }
    },
    "/v1/auth/sessions": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "List your active sessions",
        "responses": {
          "200": {
            "description": "Sessions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Session"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/sessions/{id}": {
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "Revoke one of your own other-device sessions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked"
          },
          "404": {
            "description": "Not found"
          }
        }
      }
    },
    "/v1/profile": {
      "get": {
        "tags": [
          "Profile & Memory"
        ],
        "summary": "Get detailed profile",
        "responses": {
          "200": {
            "description": "Profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Profile"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Profile & Memory"
        ],
        "summary": "Update detailed profile",
        "description": "All fields optional; only provided fields change. Timezone is validated as a real IANA name — it drives when your ALBOS memory curation runs.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "job_title": {
                    "type": "string"
                  },
                  "timezone": {
                    "type": "string"
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "en",
                      "tr"
                    ]
                  },
                  "bio": {
                    "type": "string",
                    "maxLength": 2000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Profile"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          }
        }
      }
    },
    "/v1/audit/me": {
      "get": {
        "tags": [
          "Profile & Memory"
        ],
        "summary": "Your own action history",
        "description": "Same substrate ALBOS reads to curate memory.md — also a transparency feature.",
        "responses": {
          "200": {
            "description": "Audit entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AuditEntry"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/memory": {
      "get": {
        "tags": [
          "Profile & Memory"
        ],
        "summary": "Get soul.md + memory.md",
        "responses": {
          "200": {
            "description": "Memory doc",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemoryDoc"
                }
              }
            }
          }
        }
      }
    },
    "/v1/memory/soul": {
      "patch": {
        "tags": [
          "Profile & Memory"
        ],
        "summary": "Edit your soul.md",
        "description": "User-authored identity context for ALBOS. Max 20,000 characters.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "soul_md"
                ],
                "properties": {
                  "soul_md": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved"
          },
          "400": {
            "description": "Too long"
          }
        }
      }
    },
    "/v1/memory/curate": {
      "post": {
        "tags": [
          "Profile & Memory"
        ],
        "summary": "Trigger your own memory curation on demand",
        "description": "Runs the memory-curation engine (LLM-written when a provider is available, an honest rule-based count otherwise) instead of waiting for your local night window.",
        "responses": {
          "200": {
            "description": "Curated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "entries_processed": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/organizations": {
      "get": {
        "tags": [
          "Organizations"
        ],
        "summary": "List your organizations",
        "responses": {
          "200": {
            "description": "Organizations you're a member of",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Organization"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Create an organization",
        "description": "Distributor routing is automatic: Turkey → Siyahkalem Grafik, any EU country → Evallot s.r.o. via VAT OSS, anything else → 422. Wallet is created atomically (TRY for Turkey, EUR otherwise); the creator becomes owner.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "legal_type",
                  "country"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "legal_type": {
                    "type": "string",
                    "enum": [
                      "individual",
                      "corporate"
                    ]
                  },
                  "country": {
                    "type": "string",
                    "description": "ISO 3166-1 alpha-2"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Organization"
                }
              }
            }
          },
          "422": {
            "description": "No Distributor Entity covers this country yet"
          }
        }
      }
    },
    "/v1/organizations/{id}/wallet": {
      "get": {
        "tags": [
          "Wallet & Tokens"
        ],
        "summary": "Get wallet balance (Financial role)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Wallet"
          },
          "403": {
            "description": "Insufficient role"
          },
          "404": {
            "description": "Not a member"
          }
        }
      }
    },
    "/v1/organizations/{id}/wallet/transactions": {
      "get": {
        "tags": [
          "Wallet & Tokens"
        ],
        "summary": "List wallet ledger (Financial role)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Last 100 transactions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WalletTransaction"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/organizations/{id}/wallet/credit": {
      "post": {
        "tags": [
          "Wallet & Tokens"
        ],
        "summary": "Record a bank-transfer credit (staff only)",
        "description": "Bank-only payment doctrine: credits enter via reconciliation, never a self-service card flow.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_minor"
                ],
                "properties": {
                  "amount_minor": {
                    "type": "integer"
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New balance"
          },
          "403": {
            "description": "Staff only"
          },
          "409": {
            "description": "Balance would go negative"
          }
        }
      }
    },
    "/v1/organizations/{id}/tokens": {
      "get": {
        "tags": [
          "Wallet & Tokens"
        ],
        "summary": "Get AI-token balance",
        "description": "Tokens fund AI operations across every LayerBrick brand and never convert to money.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Balance"
          }
        }
      }
    },
    "/v1/organizations/{id}/tokens/grant": {
      "post": {
        "tags": [
          "Wallet & Tokens"
        ],
        "summary": "Grant AI tokens (staff only)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount"
                ],
                "properties": {
                  "amount": {
                    "type": "integer"
                  },
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New token balance"
          },
          "403": {
            "description": "Staff only"
          }
        }
      }
    },
    "/v1/organizations/{id}/members": {
      "get": {
        "tags": [
          "Organizations"
        ],
        "summary": "List org members",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Members",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Member"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Add or update a member (Admin role)",
        "description": "Upserts the user by email if they don't exist yet — an administrative add, not a self-service invite/accept flow.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "role"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "owner",
                      "manager",
                      "finance",
                      "developer",
                      "visitor"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Member",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Member"
                }
              }
            }
          }
        }
      }
    },
    "/v1/organizations/{id}/api-keys": {
      "get": {
        "tags": [
          "API Keys"
        ],
        "summary": "List an org's API keys (Admin role)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Keys",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiKey"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "API Keys"
        ],
        "summary": "Create an API key (Admin role)",
        "description": "The plaintext `lb_live_...` token is returned exactly once, in this response — only its SHA-256 hash is stored. Keys never carry owner authority; role defaults to developer.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "manager",
                      "finance",
                      "developer",
                      "visitor"
                    ],
                    "default": "developer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key created (token shown once)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "$ref": "#/components/schemas/ApiKey"
                    },
                    "token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/organizations/{id}/api-keys/{key_id}": {
      "delete": {
        "tags": [
          "API Keys"
        ],
        "summary": "Revoke an API key (Admin role)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "key_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked"
          },
          "404": {
            "description": "Not found or already revoked"
          }
        }
      }
    },
    "/v1/organizations/{id}/kyc": {
      "post": {
        "tags": [
          "KYC"
        ],
        "summary": "Submit KYC (Admin role)",
        "description": "Required fields depend on the org's legal_type: individual needs full_name + national_id; corporate needs company_name + tax_id. Sets org kyc_status to pending. Only one submission may be pending at a time (409 otherwise). Once ever approved, the organization's legal identity locks — a further submission re-opens review without touching the current record until the new one is approved.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "fields",
                  "address",
                  "notice_acked"
                ],
                "properties": {
                  "fields": {
                    "type": "object",
                    "description": "individual: full_name, national_id. corporate: company_name, tax_id, registration_number (optional)."
                  },
                  "address": {
                    "type": "object",
                    "required": [
                      "line1",
                      "city",
                      "postal_code",
                      "country"
                    ],
                    "properties": {
                      "line1": {
                        "type": "string"
                      },
                      "line2": {
                        "type": "string"
                      },
                      "city": {
                        "type": "string"
                      },
                      "region": {
                        "type": "string"
                      },
                      "postal_code": {
                        "type": "string"
                      },
                      "country": {
                        "type": "string"
                      }
                    }
                  },
                  "notice_acked": {
                    "type": "boolean",
                    "description": "Must be true — acknowledges the privacy notice explaining why this data is collected. This is NOT consent in the GDPR/KVKK sense: the legal basis is contract-necessity/legal-obligation (invoicing, tax law), not consent."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Submitted"
          },
          "400": {
            "description": "Missing required field for this legal_type"
          }
        }
      },
      "get": {
        "tags": [
          "KYC"
        ],
        "summary": "List an org's KYC submission history",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Submissions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/KYCSubmission"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/kyc": {
      "get": {
        "tags": [
          "KYC"
        ],
        "summary": "Cross-org pending KYC queue (staff only)",
        "responses": {
          "200": {
            "description": "Pending submissions"
          },
          "403": {
            "description": "Staff only"
          }
        }
      }
    },
    "/v1/admin/kyc/{id}/approve": {
      "post": {
        "tags": [
          "KYC"
        ],
        "summary": "Approve a KYC submission (staff only)",
        "description": "Sets org kyc_status to verified and increments kyc_tier by one.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "notes": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved"
          },
          "409": {
            "description": "Already reviewed"
          }
        }
      }
    },
    "/v1/admin/kyc/{id}/reject": {
      "post": {
        "tags": [
          "KYC"
        ],
        "summary": "Reject a KYC submission (staff only)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "notes": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected"
          },
          "409": {
            "description": "Already reviewed"
          }
        }
      }
    },
    "/v1/albos": {
      "post": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Talk to ALBOS",
        "description": "LLM-backed agent (NVIDIA NIM by default, Gemini alternate; staff select the model), with automatic fallback to a fixed rule-based matcher if no provider is reachable. Three autonomy tiers: full autonomy (read-only wallet/tokens/org/kyc/session/profile queries), logged autonomy (job title / bio updates, executed immediately and audited), and confirmation-required (create_org, credit_wallet, grant_tokens, revoke_session — staged, returned as a confirmation_id + human-readable action_summary, executed only via POST /v1/albos/confirm). Staff callers also get platform tools.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message"
                ],
                "properties": {
                  "message": {
                    "type": "string"
                  },
                  "org_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Optional — scopes read-only queries to one organization."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ALBOS reply",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlbosReply"
                }
              }
            }
          }
        }
      }
    },
    "/v1/albos/confirm": {
      "post": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Execute a staged ALBOS action",
        "description": "The other half of the confirmation-required tier — nothing has any real-world effect until this is called. Staff-gated actions (credit_wallet, grant_tokens) re-check staff status at confirm time, not just at staging time.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "confirmation_id"
                ],
                "properties": {
                  "confirmation_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Executed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "action": {
                      "type": "string"
                    },
                    "result": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Belongs to a different user, or staff permission was revoked since staging"
          },
          "404": {
            "description": "Unknown confirmation_id"
          },
          "409": {
            "description": "Already confirmed"
          },
          "410": {
            "description": "Expired (10-minute TTL)"
          }
        }
      }
    },
    "/v1/audit": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "Platform-wide audit trail (staff only)",
        "responses": {
          "200": {
            "description": "Last 200 entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AuditEntry"
                  }
                }
              }
            }
          }
        },
        "403": {
          "description": "Staff only"
        }
      }
    },
    "/v1/admin/stats": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "Platform stats (staff only)",
        "responses": {
          "200": {
            "description": "Users, orgs, sessions, api keys, tokens, wallet totals per currency"
          }
        }
      }
    },
    "/v1/admin/organizations": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "All organizations with billing/KYC context (staff only)",
        "responses": {
          "200": {
            "description": "Organizations"
          }
        }
      }
    },
    "/v1/admin/users": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "All users (staff only)",
        "responses": {
          "200": {
            "description": "Users, most recent 200"
          }
        }
      }
    },
    "/v1/auth/mfa": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Current 2-step verification status",
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MFAStatus"
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/mfa/enroll": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Begin TOTP enrollment",
        "description": "Generates a secret and otpauth:// QR — not yet active until /enable.",
        "responses": {
          "200": {
            "description": "Secret + QR",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string"
                    },
                    "qr": {
                      "type": "string",
                      "description": "data: URI PNG"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/mfa/enable": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Confirm enrollment and turn 2-step verification on",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enabled — one-time backup codes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "backup_codes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid code"
          }
        }
      }
    },
    "/v1/auth/mfa/disable": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Turn off 2-step verification",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Disabled"
          }
        }
      }
    },
    "/v1/auth/mfa/backup-codes": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Regenerate backup codes",
        "description": "Invalidates all previous backup codes.",
        "responses": {
          "200": {
            "description": "New codes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "backup_codes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/auth/mfa/test": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Verify the current TOTP code works (setup wizard's confirmation step)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Valid"
          },
          "400": {
            "description": "Invalid code"
          }
        }
      }
    },
    "/v1/auth/mfa/verify": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Complete login when 2-step verification is required",
        "description": "Called after /v1/auth/verify returns {mfa_required:true, mfa_token}. Accepts either the current TOTP code or a single-use backup code.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "mfa_token",
                  "code"
                ],
                "properties": {
                  "mfa_token": {
                    "type": "string"
                  },
                  "code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{session_token}"
          },
          "400": {
            "description": "Invalid code or expired mfa_token"
          }
        }
      }
    },
    "/v1/auth/sessions/revoke-all": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Sign out everywhere except the current session",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/v1/profile/avatar": {
      "post": {
        "tags": [
          "Profile"
        ],
        "summary": "Upload a profile picture",
        "description": "multipart/form-data, field \"file\". ≤2MB, must decode as PNG/JPEG/GIF, downscaled server-side to a 512×512 PNG (also strips EXIF).",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{avatar_url}"
          },
          "413": {
            "description": "Too large"
          },
          "400": {
            "description": "Not a valid image"
          }
        }
      },
      "delete": {
        "tags": [
          "Profile"
        ],
        "summary": "Remove profile picture (reverts to generated initials)",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/v1/organizations/{id}": {
      "get": {
        "tags": [
          "Organizations"
        ],
        "summary": "Organization detail",
        "description": "Includes your_role, member/asset counts, wallet snapshot, tokens, and — once KYC-verified — the locked legal identity.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Detail",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "organization": {
                      "$ref": "#/components/schemas/OrganizationDetail"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Organizations"
        ],
        "summary": "Rename organization (Admin)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Renamed"
          }
        }
      },
      "delete": {
        "tags": [
          "Organizations"
        ],
        "summary": "Delete organization (owner only)",
        "description": "Guarded: refuses if the wallet balance is non-zero.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "409": {
            "description": "Non-zero wallet balance"
          }
        }
      }
    },
    "/v1/organizations/{id}/leave": {
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Leave an organization",
        "description": "Any member may leave except the sole remaining owner.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Left"
          },
          "409": {
            "description": "Last owner cannot leave"
          }
        }
      }
    },
    "/v1/organizations/{id}/members/{user_id}": {
      "delete": {
        "tags": [
          "Organizations"
        ],
        "summary": "Remove a member (Admin)",
        "description": "Cannot remove the last owner.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removed"
          },
          "409": {
            "description": "Last owner"
          }
        }
      },
      "patch": {
        "tags": [
          "Organizations"
        ],
        "summary": "Set a member's AI/token access (Admin)",
        "description": "Lets an org admin block a specific teammate's ALBOS access outright, or cap how many of the org's tokens they may personally spend. Enforced on every /v1/albos call — a blocked/over-limit member gets a friendly reply and the request never reaches an LLM provider.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ai_enabled": {
                    "type": "boolean"
                  },
                  "token_limit": {
                    "type": "integer",
                    "format": "int64",
                    "nullable": true,
                    "description": "null = no personal cap"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          }
        }
      }
    },
    "/v1/organizations/{id}/invites": {
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Invite a teammate by email (Admin)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "role"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "manager",
                      "finance",
                      "developer",
                      "visitor"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invite created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invite"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Organizations"
        ],
        "summary": "List invites (Admin)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invites",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Invite"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/organizations/{id}/invites/{invite_id}": {
      "delete": {
        "tags": [
          "Organizations"
        ],
        "summary": "Revoke a pending invite (Admin)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "invite_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked"
          }
        }
      }
    },
    "/v1/invites/{token}/accept": {
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Accept an invite",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The invite token from the accept_url"
          }
        ],
        "responses": {
          "200": {
            "description": "Joined — {org_id}"
          },
          "410": {
            "description": "Expired"
          }
        }
      }
    },
    "/v1/organizations/{id}/assets": {
      "get": {
        "tags": [
          "Organizations"
        ],
        "summary": "List an org's asset registry (documents/logos/links)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Assets",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/OrgAsset"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Add an asset (Admin)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kind",
                  "name"
                ],
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "document",
                      "logo",
                      "link",
                      "other"
                    ]
                  },
                  "name": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Added"
          }
        }
      }
    },
    "/v1/organizations/{id}/assets/{asset_id}": {
      "delete": {
        "tags": [
          "Organizations"
        ],
        "summary": "Delete an asset (Admin)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "asset_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          }
        }
      }
    },
    "/v1/organizations/{id}/invoices": {
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "List invoices and proformas for an org (Financial)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Documents",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Invoice"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/invoices/{id}": {
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "Invoice/proforma JSON detail (Financial)",
        "description": "Header + line items + every payment applied. The HTML render at .../html is a live preview only — never the authoritative filed document; see legal_document_url for that.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Detail",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invoice": {
                      "$ref": "#/components/schemas/Invoice"
                    },
                    "lines": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/InvoiceLine"
                      }
                    },
                    "payments": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Payment"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/invoices/{id}/html": {
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "Printable invoice/proforma preview (Financial)",
        "description": "Self-contained HTML with a Print/Save-as-PDF button. Shows a PROFORMA banner when kind=proforma, payments applied, and a download link when a legal document has been attached.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML document",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/organizations/{id}/charges": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Record a charge (**Staff only**, finance)",
        "description": "Debits the wallet immediately (real-time balance); an invoice later just documents already-applied charges.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "description",
                  "amount_minor"
                ],
                "properties": {
                  "description": {
                    "type": "string"
                  },
                  "amount_minor": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1
                  },
                  "brand": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Recorded"
          }
        }
      }
    },
    "/v1/admin/organizations/{id}/invoices": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Generate an invoice or proforma (**Staff only**, finance)",
        "description": "A real invoice (kind=invoice, default) always rolls up already-charged, already wallet-debited pending charges — never freeform lines, so it can never exist without matching wallet movement. A proforma (kind=proforma) can either quote pending charges without finalizing them (status='quoted', reversible, no wallet impact) or use freeform `lines` for an advance-payment estimate before anything's been charged.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "invoice",
                      "proforma"
                    ],
                    "default": "invoice"
                  },
                  "charge_ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Optional subset of pending charges; empty = all pending"
                  },
                  "lines": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "description": {
                          "type": "string"
                        },
                        "amount_minor": {
                          "type": "integer",
                          "format": "int64"
                        }
                      }
                    },
                    "description": "Proforma only — freeform estimate lines with no charge linkage"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — {id, number, total_minor, kind}"
          },
          "422": {
            "description": "No matching pending charges"
          }
        }
      }
    },
    "/v1/admin/invoices/{id}/convert-to-invoice": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Convert a proforma to a real invoice (**Staff only**, finance)",
        "description": "Happens in place — same row, re-numbered from the real invoice sequence, kind flipped, and any charges it quoted flipped from quoted to invoiced. Not a duplicate row.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Converted — {id, number}"
          },
          "400": {
            "description": "Not a proforma"
          }
        }
      }
    },
    "/v1/admin/organizations/{id}/wallet/adjust": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Manual wallet adjustment / refund (**Staff only**, finance)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_minor",
                  "reason"
                ],
                "properties": {
                  "amount_minor": {
                    "type": "integer",
                    "format": "int64",
                    "description": "Positive credits, negative debits"
                  },
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Adjusted — {balance_minor}"
          }
        }
      }
    },
    "/v1/admin/invoices/{id}/mark-paid": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Manually mark an invoice paid (**Staff only**, finance)",
        "description": "An EXCEPTIONAL override for write-offs or money that arrived outside tracking — does NOT move wallet money and does NOT log a payment row. Prefer POST .../payments for a real bank transfer, which does both atomically and leaves a payment trail.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Marked paid"
          },
          "409": {
            "description": "Already paid or void"
          }
        }
      }
    },
    "/v1/admin/invoices/{id}/legal-document": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Attach the real, externally-issued legal invoice (**Staff only**, finance)",
        "description": "multipart/form-data, field \"file\". ≤15MB, verified as a real PDF by magic bytes. This is the actual filed document (e.g. e-Fatura) — the platform's own HTML render is a preview only.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{legal_document_url}"
          },
          "400": {
            "description": "Not a PDF"
          },
          "413": {
            "description": "Too large"
          }
        }
      },
      "delete": {
        "tags": [
          "Billing"
        ],
        "summary": "Remove the attached legal document (**Staff only**, finance)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removed"
          }
        }
      }
    },
    "/v1/organizations/{id}/payments": {
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "Payment history for an org (Financial)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Payments",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Payment"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/organizations/{id}/payments": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Record a payment (**Staff only**, finance)",
        "description": "The primary path for a real bank transfer: logs the payment (amount/method/reference/date — not just a free-text wallet note), credits the wallet, and — if allocated to an invoice — advances its paid_minor/status (issued→partially_paid→paid), all atomically. Supersedes the old disconnected mark-paid-status-flip + separately-credit-the-wallet convention.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_minor"
                ],
                "properties": {
                  "amount_minor": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1
                  },
                  "currency": {
                    "type": "string",
                    "description": "Optional; defaults to the org's wallet currency and must match it if given"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "bank_transfer",
                      "manual",
                      "other"
                    ],
                    "default": "bank_transfer"
                  },
                  "reference": {
                    "type": "string"
                  },
                  "received_at": {
                    "type": "string",
                    "format": "date",
                    "description": "YYYY-MM-DD, defaults to today"
                  },
                  "invoice_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Optional — allocate to a specific invoice"
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Recorded — {id, wallet_balance_minor}"
          },
          "409": {
            "description": "Invoice is void"
          }
        }
      }
    },
    "/v1/admin/kyc/{id}/request-info": {
      "post": {
        "tags": [
          "KYC"
        ],
        "summary": "Ask for corrections (**Staff only**, support)",
        "description": "Sets org kyc_status to action_needed and records which fields need correction — visible to the customer, who must submit a fresh (not edited) submission.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "notes"
                ],
                "properties": {
                  "notes": {
                    "type": "string"
                  },
                  "requested_fields": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sent back for changes"
          }
        }
      }
    },
    "/v1/admin/kyc/purge-sweep": {
      "post": {
        "tags": [
          "KYC"
        ],
        "summary": "Manually run the data-minimization purge sweep (founder only)",
        "description": "Redacts the raw fields payload of any decided submission past its 180-day purge_at deadline, keeping only status/notes/timestamps for audit. Also runs automatically once a day.",
        "responses": {
          "200": {
            "description": "{purged: <count>}"
          }
        }
      }
    },
    "/v1/albos/reject": {
      "post": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Cancel a staged action",
        "description": "The chat UI's Cancel button. Deletes the row — the confirmation_id becomes permanently unusable.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "confirmation_id"
                ],
                "properties": {
                  "confirmation_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cancelled"
          },
          "404": {
            "description": "Unknown, already resolved, or not yours"
          }
        }
      }
    },
    "/v1/albos/conversations": {
      "get": {
        "tags": [
          "ALBOS"
        ],
        "summary": "List your ALBOS conversation history",
        "description": "Each closed conversation carries a ≤150-word AI-written summary.",
        "responses": {
          "200": {
            "description": "Conversations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AlbosConversation"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/albos/conversations/{id}": {
      "get": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Full transcript of one conversation",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Messages"
          }
        }
      }
    },
    "/v1/albos/conversations/close": {
      "post": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Close the current conversation",
        "description": "Triggers the AI to write its ≤150-word summary.",
        "responses": {
          "200": {
            "description": "Closed"
          }
        }
      }
    },
    "/v1/admin/albos/config": {
      "get": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Current ALBOS engine (**Staff only**)",
        "responses": {
          "200": {
            "description": "{provider, model, providers_available}"
          }
        }
      },
      "put": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Switch ALBOS's LLM at runtime (**Staff only**)",
        "description": "Changes language understanding only — permission checks and the stage/confirm rule are enforced in Go regardless of model.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "provider"
                ],
                "properties": {
                  "provider": {
                    "type": "string",
                    "enum": [
                      "nvidia",
                      "gemini"
                    ]
                  },
                  "model": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Switched"
          }
        }
      }
    },
    "/v1/admin/albos/models": {
      "get": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Live model catalogue (**Staff only**)",
        "description": "NVIDIA's full catalogue fetched live + Gemini's fixed set.",
        "responses": {
          "200": {
            "description": "Models"
          }
        }
      }
    },
    "/v1/admin/proposals": {
      "get": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Platform-improvement proposals (**Staff only**)",
        "description": "Drafted by the staff agent tier (deliberately proposals-only — the agent never modifies the platform directly) or added for review.",
        "responses": {
          "200": {
            "description": "Proposals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PlatformProposal"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/proposals/{id}/status": {
      "post": {
        "tags": [
          "ALBOS"
        ],
        "summary": "Update a proposal's status (**Staff only**)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "draft",
                      "accepted",
                      "rejected",
                      "done"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          }
        }
      }
    },
    "/v1/admin/audit/search": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "Search the audit log (**Staff only**)",
        "description": "Query params: actor, action, subject, from, to, cursor (pagination).",
        "responses": {
          "200": {
            "description": "Entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AuditEntry"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/users/{id}": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "User detail drill-down (**Staff only**)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Detail"
          }
        }
      }
    },
    "/v1/admin/users/{id}/suspend": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Suspend a user (**Staff only**, support/founder)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suspended"
          }
        }
      }
    },
    "/v1/admin/users/{id}/unsuspend": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Unsuspend a user (**Staff only**, support/founder)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Unsuspended"
          }
        }
      }
    },
    "/v1/admin/users/{id}/logout-all": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Force-revoke every session for a user (**Staff only**)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked"
          }
        }
      }
    },
    "/v1/admin/users/{id}/staff-role": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Set a user's staff role (founder only)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "staff_role"
                ],
                "properties": {
                  "staff_role": {
                    "type": "string",
                    "enum": [
                      "",
                      "founder",
                      "support",
                      "ops",
                      "finance",
                      "abuse"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          }
        }
      }
    },
    "/v1/admin/organizations/{id}": {
      "get": {
        "tags": [
          "Admin"
        ],
        "summary": "Organization detail drill-down (**Staff only**)",
        "description": "Members, wallet ledger, invoices, pending charges, payments, KYC history — the substrate for the Billing actions in the admin panel.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Detail"
          }
        }
      }
    },
    "/v1/admin/organizations/{id}/suspend": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Suspend an organization (**Staff only**, support/abuse/founder)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suspended"
          }
        }
      }
    },
    "/v1/admin/organizations/{id}/unsuspend": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Unsuspend an organization (**Staff only**, support/abuse/founder)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Unsuspended"
          }
        }
      }
    },
    "/v1/admin/impersonate/{id}": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "Start read-only \"View as\" (**Staff only**, support/founder)",
        "description": "Mints an lb_imp_ token that resolves to the target user but blocks every non-GET request. 30-min TTL, audited.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{impersonation_token, expires_at}"
          }
        }
      }
    },
    "/v1/admin/impersonate/end": {
      "post": {
        "tags": [
          "Admin"
        ],
        "summary": "End the current impersonation session",
        "responses": {
          "200": {
            "description": "Ended"
          }
        }
      }
    },
    "/v1/kb/categories": {
      "get": {
        "tags": [
          "Knowledge base"
        ],
        "summary": "List published categories",
        "responses": {
          "200": {
            "description": "Categories",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/KBCategory"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/kb/articles": {
      "get": {
        "tags": [
          "Knowledge base"
        ],
        "summary": "List/search published articles",
        "description": "Query params: category (slug), q (text search over title+body).",
        "responses": {
          "200": {
            "description": "Articles"
          }
        }
      }
    },
    "/v1/kb/articles/{slug}": {
      "get": {
        "tags": [
          "Knowledge base"
        ],
        "summary": "Read one published article",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Article",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KBArticle"
                }
              }
            }
          },
          "404": {
            "description": "Not found or not published"
          }
        }
      }
    },
    "/v1/admin/kb/articles": {
      "get": {
        "tags": [
          "Knowledge base"
        ],
        "summary": "List all articles incl. drafts (**Staff only**, support)",
        "responses": {
          "200": {
            "description": "Articles"
          }
        }
      },
      "post": {
        "tags": [
          "Knowledge base"
        ],
        "summary": "Create/update an article (**Staff only**, support)",
        "description": "Upsert by slug.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "slug",
                  "title"
                ],
                "properties": {
                  "category_slug": {
                    "type": "string"
                  },
                  "slug": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "body_md": {
                    "type": "string"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "draft",
                      "published"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved"
          }
        }
      }
    },
    "/v1/admin/kb/articles/{slug}": {
      "get": {
        "tags": [
          "Knowledge base"
        ],
        "summary": "Read any article incl. drafts (**Staff only**, support)",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Article"
          }
        }
      },
      "delete": {
        "tags": [
          "Knowledge base"
        ],
        "summary": "Delete an article (**Staff only**, support)",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          }
        }
      }
    },
    "/v1/admin/distributors": {
      "get": {
        "tags": [
          "Distributors"
        ],
        "summary": "List distributor entities (**Staff only**, finance)",
        "responses": {
          "200": {
            "description": "Distributors",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Distributor"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Distributors"
        ],
        "summary": "Create a distributor entity (**Staff only**, finance)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "country"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "country": {
                    "type": "string",
                    "description": "2-letter, immutable after creation"
                  },
                  "legal_name": {
                    "type": "string"
                  },
                  "tax_id": {
                    "type": "string"
                  },
                  "address": {
                    "type": "string"
                  },
                  "bank_name": {
                    "type": "string"
                  },
                  "bank_iban": {
                    "type": "string"
                  },
                  "bank_swift": {
                    "type": "string"
                  },
                  "contact_email": {
                    "type": "string"
                  },
                  "contact_phone": {
                    "type": "string"
                  },
                  "notes": {
                    "type": "string"
                  },
                  "profit_pct": {
                    "type": "number"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — {id}"
          }
        }
      }
    },
    "/v1/admin/distributors/{id}": {
      "get": {
        "tags": [
          "Distributors"
        ],
        "summary": "Distributor detail (**Staff only**, finance)",
        "description": "Includes profit-share stats (computed from paid invoice totals), staff list, and client organizations routed through it.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Detail"
          }
        }
      },
      "put": {
        "tags": [
          "Distributors"
        ],
        "summary": "Full update (**Staff only**, finance)",
        "description": "Same body shape as create. Country cannot be changed.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Updated"
          }
        }
      },
      "patch": {
        "tags": [
          "Distributors"
        ],
        "summary": "Legacy narrow update (**Staff only**, finance)",
        "description": "Only name/legal_name/tax_id/address — prefer PUT for the full field set (banking, profit_pct, contact).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Updated"
          }
        }
      },
      "delete": {
        "tags": [
          "Distributors"
        ],
        "summary": "Delete a distributor entity (**Staff only**, finance)",
        "description": "Refuses if any organization still routes through it.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "409": {
            "description": "Still has organizations routed to it"
          }
        }
      }
    },
    "/v1/admin/distributors/{id}/staff": {
      "post": {
        "tags": [
          "Distributors"
        ],
        "summary": "Link a user as distributor staff (**Staff only**, finance)",
        "description": "Upserts the user by email (same no-duplicate-collection pattern as org invites) and links them as an observer — never LayerBrick staff.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Linked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DistributorStaffMember"
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/distributors/{id}/staff/{user_id}": {
      "delete": {
        "tags": [
          "Distributors"
        ],
        "summary": "Unlink distributor staff (**Staff only**, finance)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Unlinked"
          }
        }
      }
    },
    "/v1/distributor/overview": {
      "get": {
        "tags": [
          "Distributors"
        ],
        "summary": "Your distributor entity's identity + revenue/profit stats",
        "description": "For distributor STAFF only (linked via distributor_staff, never LayerBrick staff). Scoped via the caller's own link — there is no parameter to reach another entity's data.",
        "responses": {
          "200": {
            "description": "Overview"
          },
          "404": {
            "description": "You are not staff of a distributor entity"
          }
        }
      }
    },
    "/v1/distributor/organizations": {
      "get": {
        "tags": [
          "Distributors"
        ],
        "summary": "Client organizations routed through your entity",
        "responses": {
          "200": {
            "description": "Organizations"
          },
          "404": {
            "description": "You are not staff of a distributor entity"
          }
        }
      }
    },
    "/v1/distributor/invoices": {
      "get": {
        "tags": [
          "Distributors"
        ],
        "summary": "Invoices issued by your entity",
        "responses": {
          "200": {
            "description": "Invoices"
          },
          "404": {
            "description": "You are not staff of a distributor entity"
          }
        }
      }
    },
    "/v1/organizations/{id}/payment-claims": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Submit a payment claim (Financial)",
        "description": "Self-service half of the payment flow: a customer states they've sent a bank transfer, with the reference so staff can verify it. Nothing moves yet — the wallet and any invoice are untouched until a staff member approves the claim, which then runs through the exact same recordPayment transaction a staff-entered payment uses.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_minor",
                  "reference"
                ],
                "properties": {
                  "amount_minor": {
                    "type": "integer",
                    "format": "int64",
                    "minimum": 1
                  },
                  "currency": {
                    "type": "string",
                    "description": "Optional; defaults to the org's wallet currency and must match it if given"
                  },
                  "reference": {
                    "type": "string",
                    "description": "Required — the bank reference/description on the transfer"
                  },
                  "invoice_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Optional — which invoice this is meant to settle"
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Submitted — {id, status: pending}"
          },
          "400": {
            "description": "Missing reference or currency mismatch"
          }
        }
      },
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "List your organization's own payment claims (Financial)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Claims",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PaymentClaim"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/payment-claims": {
      "get": {
        "tags": [
          "Billing"
        ],
        "summary": "Cross-org pending payment-claim queue (**Staff only**, finance)",
        "description": "Same pattern as the KYC review queue.",
        "responses": {
          "200": {
            "description": "Pending claims",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PaymentClaim"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/admin/payment-claims/{id}/approve": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Approve a payment claim (**Staff only**, finance)",
        "description": "Runs the claim's amount/reference/invoice through the same recordPayment transaction a staff-entered payment uses — approval authorizes the same path, it doesn't reinvent money movement. 409 if the claim was already reviewed.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{payment_id, wallet_balance_minor}"
          },
          "409": {
            "description": "Already reviewed"
          }
        }
      }
    },
    "/v1/admin/payment-claims/{id}/reject": {
      "post": {
        "tags": [
          "Billing"
        ],
        "summary": "Reject a payment claim (**Staff only**, finance)",
        "description": "A reason is required — the customer sees it.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "notes"
                ],
                "properties": {
                  "notes": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected"
          },
          "400": {
            "description": "Reason required"
          },
          "409": {
            "description": "Already reviewed"
          }
        }
      }
    },
    "/v1/organizations/{id}/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List an organization's projects",
        "description": "Projects group resources across every brand — Comphive servers today, more as brands come online. Any org member can list.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Projects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Project"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Create a project (Technical role: owner/manager/developer)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 80
                  },
                  "description": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — {id}"
          },
          "409": {
            "description": "A project with this name already exists in this organization"
          }
        }
      }
    },
    "/v1/projects/{id}": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Project detail",
        "description": "This is what other brands call server-to-server (forwarding the caller's bearer token) to validate a project_id and learn its org_id before accepting a resource creation scoped to it.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            }
          },
          "404": {
            "description": "Not found"
          }
        }
      },
      "patch": {
        "tags": [
          "Projects"
        ],
        "summary": "Rename/update a project (Technical role)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          },
          "409": {
            "description": "Name conflict"
          }
        }
      },
      "delete": {
        "tags": [
          "Projects"
        ],
        "summary": "Delete a project (Admin role: owner/manager)",
        "description": "Removes the Core record only — other brands' own resources (e.g. a Comphive server) keep a project_id that simply stops resolving (404 from GET /v1/projects/{id}), the same way brands already handle a deleted/renamed organization.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          }
        }
      }
    }
  }
}