{
  "openapi": "3.0.3",
  "info": {
    "title": "APIFact console API",
    "version": "1.0.0",
    "description": "The self-service console of ADR 0016 phase 1. Its audience is the console front-end, not an integrator: authentication is an opaque, server-side session carried in a __Host- prefixed, HttpOnly, SameSite=Strict cookie, and every unsafe method additionally requires an Origin header naming a configured console origin. This is a SEPARATE document from the machine API at /api/v2/openapi.json on purpose -- the two have different audiences, different credentials and different failure modes, and a client generated from one can never call the other. The tenant is never taken from a request: it is derived from the session plus the company the user selects, and the membership check and the assignment of app.tenant_id happen in a single database call (auth.bind_console_company), which is the invariant of ADR 0016 point 5. THIS PARAGRAPH USED TO END by declaring that there is deliberately no route attaching a company to an organization, because it would let anyone claim an arbitrary RUC -- a sentence that survived migration 000065 shipping POST /console/v1/organizations/{organizationId}/companies into this very document, and was therefore contradicted by the paths below it for as long as anybody read it. The alta is here, and the objection it answered is answered where the route is described: the claim confers nothing until SUNAT accepts a comprobante signed with a certificate issued to that RUC, which is proof of control demanded by the party that can check it, and what the platform guarantees meanwhile is attribution rather than prevention. Everything an operator used to be needed for -- the alta, the certificate, the API credential, and now the organization credential a platform provisions its own clients with -- is on this surface."
  },
  "servers": [
    {
      "url": "https://apifact.fac-360.com",
      "description": "Production. The real organization: its members and their roles, its companies, the certificates that sign their comprobantes and the credentials that issue them. Sessions belong to this edge alone."
    },
    {
      "url": "https://apifact-staging.fac-360.com",
      "description": "Staging. A separate database with separate accounts, sessions and companies -- a production account does not exist here and cannot sign in. Everything its companies issue goes to SUNAT beta, so nothing produced through it is fiscally valid."
    }
  ],
  "tags": [
    {
      "name": "Identity",
      "description": "Sign-up, verification, sessions and the second factor"
    },
    {
      "name": "Organizations",
      "description": "Members, roles and invitations"
    },
    {
      "name": "Companies",
      "description": "The companies a session can operate, and their data"
    }
  ],
  "components": {
    "securitySchemes": {
      "consoleSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-apf_console",
        "description": "Set by POST /console/v1/sessions. HttpOnly, Secure, SameSite=Strict, Path=/, __Host- prefixed. It is never readable by JavaScript and there is no header alternative: accepting both carriers would let an attacker choose the weaker one."
      }
    },
    "schemas": {
      "ConsoleRegistrationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "email",
          "password",
          "organizationName"
        ],
        "properties": {
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254
          },
          "password": {
            "type": "string",
            "minLength": 12,
            "maxLength": 1024
          },
          "organizationName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        }
      },
      "ConsoleTokenRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "type": "string",
            "minLength": 8,
            "maxLength": 120
          }
        }
      },
      "ConsoleLoginRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "email",
          "password"
        ],
        "properties": {
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254
          },
          "password": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1024
          },
          "totpCode": {
            "type": "string",
            "pattern": "^[0-9]{6}$"
          }
        }
      },
      "ConsoleChangePasswordRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "email",
          "currentPassword",
          "newPassword"
        ],
        "properties": {
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254
          },
          "currentPassword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1024
          },
          "newPassword": {
            "type": "string",
            "minLength": 12,
            "maxLength": 1024
          }
        }
      },
      "ConsoleInvitationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "email",
          "role"
        ],
        "properties": {
          "email": {
            "type": "string",
            "minLength": 3,
            "maxLength": 254
          },
          "role": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          }
        }
      },
      "ConsoleEnrolCertificateRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "environment",
          "pfxBase64",
          "pfxPassword",
          "solUser",
          "solPassword"
        ],
        "properties": {
          "environment": {
            "type": "string",
            "enum": [
              "BETA",
              "PRODUCTION"
            ]
          },
          "pfxBase64": {
            "type": "string",
            "minLength": 4,
            "maxLength": 700000
          },
          "pfxPassword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          },
          "solUser": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "solPassword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          }
        }
      },
      "ConsoleCertificateList": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "schemaVersion",
          "requestId",
          "companyId",
          "certificates"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "certificates": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "ConsoleCertificateEnrolled": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "schemaVersion",
          "requestId"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "ConsoleCertificateActivation": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "schemaVersion",
          "requestId"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "ConsoleCertificateActivationStarted": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "schemaVersion",
          "requestId",
          "activationId",
          "configurationId",
          "version",
          "status",
          "certificateStatus",
          "mechanism"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "activationId": {
            "type": "string",
            "format": "uuid"
          },
          "configurationId": {
            "type": "string",
            "format": "uuid"
          },
          "version": {
            "type": "integer"
          },
          "environment": {
            "type": "string",
            "enum": [
              "BETA",
              "PRODUCTION"
            ]
          },
          "status": {
            "type": "string"
          },
          "mechanism": {
            "type": "string",
            "enum": [
              "PROBE",
              "FIRST_ISSUE"
            ]
          },
          "certificateStatus": {
            "type": "string",
            "enum": [
              "DRAFT",
              "PENDING_FIRST_ISSUE"
            ]
          },
          "probe": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true
          },
          "replay": {
            "type": "boolean"
          }
        }
      },
      "ConsoleCreateCompanyRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ruc",
          "legalName",
          "environment"
        ],
        "properties": {
          "ruc": {
            "type": "string",
            "pattern": "^[0-9]{11}$"
          },
          "legalName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "environment": {
            "type": "string",
            "enum": [
              "BETA",
              "PRODUCTION"
            ]
          }
        }
      },
      "ConsoleMemberRoleRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          }
        }
      },
      "ConsoleMfaEnrolmentRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "secret",
          "code"
        ],
        "properties": {
          "secret": {
            "type": "string",
            "pattern": "^[A-Z2-7]{16,128}$"
          },
          "code": {
            "type": "string",
            "pattern": "^[0-9]{6}$"
          }
        }
      },
      "ConsoleMintCredentialRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "scopes"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "What this credential is for, shown in the listing next to its public prefix. It is stored on the credential and recorded on the audit event, so a key can still be identified after whoever created it has left."
          },
          "scopes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 16,
            "items": {
              "type": "string",
              "enum": [
                "artifacts:read",
                "certificates:manage",
                "consultations:cpe",
                "consultations:dni",
                "consultations:read",
                "documents:create",
                "documents:pdf",
                "documents:read",
                "documents:submit",
                "documents:validate",
                "operations:read",
                "webhooks:manage"
              ]
            },
            "description": "The same vocabulary the provisioning API mints from, because both go through the same database function. companies:manage is not among them and cannot be. certificates:manage is grantable only by ADMIN and above: it replaces the key that signs this company's comprobantes, so a DEVELOPER who could mint it would hold an ADMIN capability through a token."
          },
          "expiresInDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "default": 90
          }
        }
      },
      "ConsoleMintOrganizationCredentialRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name",
          "scopes"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "What this credential is for, shown in the listing next to its public prefix and recorded on the audit event, so it can still be identified after whoever created it has left."
          },
          "scopes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 2,
            "items": {
              "type": "string",
              "enum": [
                "companies:manage",
                "organizations:read"
              ]
            },
            "description": "The two scopes an organization credential may hold, and they are offered separately on purpose. companies:manage can register a company under ANY RUC in Peru, enrol its certificate and mint the credentials that issue its comprobantes -- the privilege escalation ADR 0016 point 3 names. organizations:read can do none of that: it reads the organization's companies, their certificate state and their consumption, which is what a monitoring job or a billing reconciliation needs. companies:manage already satisfies organizations:read at check time, so asking for both stores a second row that grants nothing extra. No documents:* scope is admissible here and none ever will be: auth.organization_credential_scopes refuses them, which is one of the four reasons an organization credential can never issue a comprobante."
          },
          "expiresInDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365,
            "default": 90
          }
        },
        "example": {
          "name": "provisioning · staging",
          "scopes": [
            "organizations:read"
          ],
          "expiresInDays": 90
        }
      },
      "ConsoleError": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "error"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "error": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {}
            }
          }
        }
      },
      "ConsoleRegistrationAccepted": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "status"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "VERIFICATION_PENDING"
            ],
            "description": "The ONLY answer this route gives, whether or not the address was free. It carries no user id and no organization id, because either would tell the caller which branch it took, and the identical Argon2id cost is paid on both so the duration does not tell them either."
          }
        }
      },
      "ConsoleMembership": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "organizationId",
          "organizationName",
          "memberRole"
        ],
        "properties": {
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "organizationName": {
            "type": "string"
          },
          "memberRole": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          }
        }
      },
      "ConsoleSessionResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "userId",
          "email",
          "mfaEnrolled",
          "memberships"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string"
          },
          "mfaEnrolled": {
            "type": "boolean"
          },
          "memberships": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsoleMembership"
            }
          }
        }
      },
      "ConsoleCompanySummary": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "companyId",
          "ruc",
          "legalName",
          "status",
          "environment",
          "organizationId",
          "memberRole"
        ],
        "properties": {
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "ruc": {
            "type": "string",
            "pattern": "^[0-9]{11}$"
          },
          "legalName": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "INACTIVE"
            ]
          },
          "environment": {
            "type": "string",
            "enum": [
              "BETA",
              "PRODUCTION"
            ]
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "memberRole": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          }
        }
      },
      "ConsoleCompanyList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "companies"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "companies": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsoleCompanySummary"
            }
          }
        }
      },
      "ConsoleCompanyCreated": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "companyId",
          "ruc",
          "legalName",
          "status",
          "environment",
          "organizationId",
          "createdAt"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "ruc": {
            "type": "string",
            "pattern": "^[0-9]{11}$"
          },
          "legalName": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "INACTIVE"
            ]
          },
          "environment": {
            "type": "string",
            "enum": [
              "BETA",
              "PRODUCTION"
            ]
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConsoleCompanyResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "companyId",
          "ruc",
          "legalName",
          "status",
          "environment",
          "organizationId",
          "memberRole",
          "createdAt"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "ruc": {
            "type": "string",
            "pattern": "^[0-9]{11}$"
          },
          "legalName": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "INACTIVE"
            ]
          },
          "environment": {
            "type": "string",
            "enum": [
              "BETA",
              "PRODUCTION"
            ]
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "memberRole": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConsoleDocumentSummary": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "documentId",
          "documentType",
          "series",
          "number",
          "state",
          "fiscalState",
          "stateVersion",
          "environment",
          "createdAt",
          "updatedAt"
        ],
        "properties": {
          "documentId": {
            "type": "string",
            "format": "uuid"
          },
          "documentType": {
            "type": "string",
            "enum": [
              "01",
              "03",
              "07",
              "08"
            ]
          },
          "series": {
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "fiscalState": {
            "type": "string",
            "enum": [
              "ISSUED",
              "REPORTED",
              "VOID_REQUESTED",
              "VOIDED"
            ],
            "description": "Separate from state because a factura withdrawn by an accepted comunicacion de baja is still ACCEPTED at SUNAT and no longer valid fiscally. Reporting only the first would be a lie by omission."
          },
          "stateVersion": {
            "type": "integer",
            "minimum": 1
          },
          "environment": {
            "type": "string",
            "enum": [
              "BETA",
              "PRODUCTION"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConsoleDocumentPage": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "documents",
          "nextCursor"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsoleDocumentSummary"
            }
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Keyset position on (updatedAt, documentId). Null on the last page. Opaque: pass it back verbatim as ?cursor=."
          }
        }
      },
      "ConsoleSunatVerdict": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "responseCode",
          "responseMessage",
          "classification",
          "catalogVersion",
          "finishedAt",
          "severity",
          "standing",
          "action",
          "guidance"
        ],
        "properties": {
          "responseCode": {
            "type": "string",
            "nullable": true
          },
          "responseMessage": {
            "type": "string",
            "nullable": true
          },
          "classification": {
            "type": "string",
            "nullable": true
          },
          "catalogVersion": {
            "type": "string",
            "nullable": true,
            "description": "The catalog version recorded ON THAT ATTEMPT, never the one the running bundle holds. Null for a verdict reached before migration 000048 added the column, which is a genuine 'not recorded'."
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "severity": {
            "type": "string",
            "nullable": true
          },
          "standing": {
            "type": "string",
            "nullable": true
          },
          "action": {
            "type": "string",
            "nullable": true
          },
          "guidance": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ConsoleDocumentResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "documentId",
          "documentType",
          "series",
          "number",
          "state",
          "fiscalState",
          "stateVersion",
          "environment",
          "createdAt",
          "updatedAt",
          "sunat"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "documentId": {
            "type": "string",
            "format": "uuid"
          },
          "documentType": {
            "type": "string",
            "enum": [
              "01",
              "03",
              "07",
              "08"
            ]
          },
          "series": {
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "fiscalState": {
            "type": "string",
            "enum": [
              "ISSUED",
              "REPORTED",
              "VOID_REQUESTED",
              "VOIDED"
            ]
          },
          "stateVersion": {
            "type": "integer",
            "minimum": 1
          },
          "environment": {
            "type": "string",
            "enum": [
              "BETA",
              "PRODUCTION"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "sunat": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/ConsoleSunatVerdict"
              }
            ]
          }
        }
      },
      "ConsoleArtifact": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "kind",
          "storageKind",
          "representationId",
          "version",
          "status",
          "mediaType",
          "byteSize",
          "sha256",
          "templateVersion",
          "rendererVersion",
          "errorCode",
          "readyAt",
          "downloadPath"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "nullable": true,
            "description": "The public name of a versionless artifact (signed-xml, cdr-xml, ...). Null for a versioned PDF render, which is addressed by representationId instead."
          },
          "storageKind": {
            "type": "string"
          },
          "representationId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "version": {
            "type": "integer",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "RUNNING",
              "READY",
              "FAILED"
            ]
          },
          "mediaType": {
            "type": "string"
          },
          "byteSize": {
            "type": "integer",
            "nullable": true
          },
          "sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "nullable": true
          },
          "templateVersion": {
            "type": "string",
            "nullable": true
          },
          "rendererVersion": {
            "type": "string",
            "nullable": true
          },
          "errorCode": {
            "type": "string",
            "nullable": true
          },
          "readyAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "downloadPath": {
            "type": "string",
            "nullable": true,
            "description": "Null until the artifact is READY. There is nothing to stream before."
          }
        }
      },
      "ConsoleArtifactList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "documentId",
          "artifacts"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "documentId": {
            "type": "string",
            "format": "uuid"
          },
          "artifacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsoleArtifact"
            }
          }
        }
      },
      "ConsoleUsageResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "companyId",
          "metric",
          "planCode",
          "metered",
          "periodUnit",
          "periodStart",
          "limit",
          "consumed"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "metric": {
            "type": "string"
          },
          "planCode": {
            "type": "string",
            "nullable": true
          },
          "metered": {
            "type": "boolean",
            "description": "false when nothing caps this company: no active subscription, or no plan limit for this metric. It is not the same as a limit of zero."
          },
          "periodUnit": {
            "type": "string",
            "enum": [
              "DAY",
              "MONTH"
            ]
          },
          "periodStart": {
            "type": "string",
            "format": "date"
          },
          "limit": {
            "type": "integer",
            "nullable": true
          },
          "consumed": {
            "type": "integer"
          }
        }
      },
      "ConsoleActivityEntry": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "occurredAt",
          "operationId",
          "documentId",
          "documentType",
          "series",
          "number",
          "operationType",
          "operationStatus",
          "startedAt",
          "finishedAt",
          "attemptNumber",
          "endpoint",
          "classification",
          "responseCode",
          "responseMessage",
          "catalogVersion",
          "credentialPrefix"
        ],
        "properties": {
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          },
          "operationId": {
            "type": "string",
            "format": "uuid"
          },
          "documentId": {
            "type": "string",
            "format": "uuid"
          },
          "documentType": {
            "type": "string"
          },
          "series": {
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "operationType": {
            "type": "string"
          },
          "operationStatus": {
            "type": "string"
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "attemptNumber": {
            "type": "integer",
            "nullable": true,
            "description": "Null for an operation that never reached SUNAT. One entry per attempt, never collapsed: three transport failures followed by an acceptance is a different story from one acceptance."
          },
          "endpoint": {
            "type": "string",
            "nullable": true
          },
          "classification": {
            "type": "string",
            "nullable": true
          },
          "responseCode": {
            "type": "string",
            "nullable": true
          },
          "responseMessage": {
            "type": "string",
            "nullable": true
          },
          "catalogVersion": {
            "type": "string",
            "nullable": true
          },
          "credentialPrefix": {
            "type": "string",
            "nullable": true,
            "description": "The PUBLIC selector of the API credential that started the operation (apf_v2_<uuid>_). Never the secret; no column holds one."
          }
        }
      },
      "ConsoleActivityResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "companyId",
          "entries"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsoleActivityEntry"
            }
          }
        }
      },
      "ConsoleMember": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "userId",
          "email",
          "memberRole",
          "mfaEnrolled",
          "status",
          "joinedAt"
        ],
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string"
          },
          "memberRole": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          },
          "mfaEnrolled": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "DISABLED"
            ]
          },
          "joinedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConsoleMemberList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "organizationId",
          "memberRole",
          "members"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "memberRole": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ],
            "description": "The CALLER's role in this organization."
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsoleMember"
            }
          }
        }
      },
      "ConsoleMemberRoleResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "organizationId",
          "userId",
          "memberRole",
          "revokedSessions"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "memberRole": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ],
            "nullable": true
          },
          "revokedSessions": {
            "type": "integer",
            "description": "The affected member's sessions, all of them, revoked by the same transaction. It is not what makes the change take effect -- auth.bind_console_company re-reads the role on EVERY transaction, so a demotion binds on the next statement -- it is what makes the pages that session already rendered consistent with the new role."
          }
        }
      },
      "ConsolePendingInvitation": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "invitationId",
          "email",
          "role",
          "createdAt",
          "expiresAt"
        ],
        "properties": {
          "invitationId": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConsoleInvitationList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "organizationId",
          "invitations"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "invitations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsolePendingInvitation"
            }
          }
        }
      },
      "ConsoleInvitationCreated": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "invitationId",
          "invitationToken",
          "email",
          "role",
          "expiresAt"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "invitationId": {
            "type": "string",
            "format": "uuid"
          },
          "invitationToken": {
            "type": "string",
            "description": "The secret half of the invitation link, returned EXACTLY ONCE. Only its SHA-256 is stored and no route re-reads it; a lost link is revoked and re-sent, never recovered."
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConsoleInvitationAccepted": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "organizationId",
          "memberRole"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "memberRole": {
            "type": "string",
            "enum": [
              "OWNER",
              "ADMIN",
              "DEVELOPER",
              "VIEWER"
            ]
          }
        }
      },
      "ConsoleCredentialSummary": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "credentialId",
          "name",
          "tokenPrefix",
          "scopes",
          "status",
          "expiresAt",
          "revokedAt",
          "lastUsedAt",
          "createdAt"
        ],
        "properties": {
          "credentialId": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Null for a credential minted before names existed, or by the operator script. There is nothing to invent here: a name nobody chose would be a claim about who chose it."
          },
          "tokenPrefix": {
            "type": "string",
            "description": "The PUBLIC selector, apf_v2_<uuid>_. It is the same value the activity log reports for the credential that started an operation, which is what makes the two pages joinable. The secret is not here and is not anywhere: only its SHA-256 is stored."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "REVOKED",
              "EXPIRED",
              "DISABLED"
            ],
            "description": "Computed from the same three conditions auth.lookup_api_credential decides usability with, so this page cannot call a credential live while the issuing path refuses it. Revoked credentials stay in the listing: 'what happened to the key that was in yesterday's logs' needs a row for an answer, not an absence."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConsoleCredentialList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "companyId",
          "credentials"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "credentials": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsoleCredentialSummary"
            }
          }
        }
      },
      "ConsoleMintedCredential": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "credentialId",
          "token",
          "name",
          "companyId",
          "companyRuc",
          "scopes",
          "expiresAt",
          "createdAt",
          "auditEventId"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "credentialId": {
            "type": "string",
            "format": "uuid"
          },
          "token": {
            "type": "string",
            "description": "The secret, in this response and NOWHERE ELSE. Only its SHA-256 is stored, no route re-reads it, no log line carries it: a lost token is replaced by minting another and revoking this one."
          },
          "name": {
            "type": "string"
          },
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "companyRuc": {
            "type": "string",
            "pattern": "^[0-9]{11}$"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "auditEventId": {
            "type": "string",
            "format": "uuid",
            "description": "The ops.audit_events row this minting wrote. Returned because minting a credential is a privilege escalation (ADR 0016 point 3) and the caller is entitled to the reference that records it. The credential and the event commit in one transaction, and a DEFERRABLE constraint trigger refuses the credential at COMMIT if the event is missing."
          }
        }
      },
      "ConsoleCredentialRevoked": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "companyId",
          "credentialId",
          "revokedAt"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "companyId": {
            "type": "string",
            "format": "uuid"
          },
          "credentialId": {
            "type": "string",
            "format": "uuid"
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it stopped working, which is when this call committed and not when it would have expired. auth.lookup_api_credential re-reads revoked_at on every authenticated request, so the next one already fails."
          }
        }
      },
      "ConsoleOrganizationCredentialSummary": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "credentialId",
          "name",
          "tokenPrefix",
          "scopes",
          "status",
          "expiresAt",
          "revokedAt",
          "lastUsedAt",
          "createdAt"
        ],
        "properties": {
          "credentialId": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "tokenPrefix": {
            "type": "string",
            "description": "The PUBLIC selector, apf_org_v2_<uuid>_. Unlike a company credential's prefix it appears in NO other console page -- an organization credential issues nothing, so it never reaches the activity log -- which is why this listing is OWNER and not VIEWER. The secret is not here and is not anywhere: only its SHA-256 is stored."
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "REVOKED",
              "EXPIRED",
              "DISABLED"
            ],
            "description": "Computed from the same conditions auth.lookup_organization_credential decides usability with, so this page cannot report a credential live while the provisioning API refuses it. DISABLED means the organization is SUSPENDED. Revoked credentials stay in the listing."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastUsedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConsoleOrganizationCredentialList": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "organizationId",
          "credentials"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "credentials": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConsoleOrganizationCredentialSummary"
            }
          }
        }
      },
      "ConsoleMintedOrganizationCredential": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "credentialId",
          "token",
          "name",
          "organizationId",
          "organizationName",
          "scopes",
          "expiresAt",
          "createdAt",
          "auditEventId"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "credentialId": {
            "type": "string",
            "format": "uuid"
          },
          "token": {
            "type": "string",
            "description": "The secret, in this response and NOWHERE ELSE. Only its SHA-256 is stored, no route re-reads it, no log line carries it. A lost token is replaced by minting another and revoking this one -- which is a routine sequence rather than an outage, because an organization may hold as many of these as it likes and both can be live at once."
          },
          "name": {
            "type": "string"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "organizationName": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What was STORED, read back from auth.organization_credential_scopes rather than echoed from the request, so a duplicate in the request is reported once and nothing is claimed that was not written."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "auditEventId": {
            "type": "string",
            "format": "uuid",
            "description": "The ops.audit_events row this minting wrote. Returned because this is the sharpest capability the platform grants and the caller is entitled to the reference that records it. The credential and the event commit in one transaction, and a DEFERRABLE constraint trigger on auth.organization_credentials refuses the credential at COMMIT if the event is missing -- so an unaudited organization credential is not a policy violation, it is a failed transaction, whoever the writer is."
          }
        }
      },
      "ConsoleOrganizationCredentialRevoked": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "organizationId",
          "credentialId",
          "revokedAt"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "organizationId": {
            "type": "string",
            "format": "uuid"
          },
          "credentialId": {
            "type": "string",
            "format": "uuid"
          },
          "revokedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it stopped working, which is when this call committed and not when it would have expired. auth.assert_organization_credential re-reads revoked_at on EVERY provisioning statement rather than resolving once per request, so the next call already fails."
          }
        }
      },
      "ConsoleMfaEnrolmentStarted": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "requestId",
          "secret",
          "uri",
          "qrPngDataUrl"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "enum": [
              "console.1"
            ]
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "secret": {
            "type": "string",
            "pattern": "^[A-Z2-7]+$",
            "description": "Base32 TOTP seed, stored NOWHERE until POST /console/v1/mfa proves a code can be produced from it. Echo it back with that code."
          },
          "uri": {
            "type": "string"
          },
          "qrPngDataUrl": {
            "type": "string",
            "pattern": "^data:image/png;base64,",
            "description": "The uri above, rendered as a QR PNG and inlined as a data URI. It is generated HERE and not in the browser because the console front-end has no build step and refuses CDNs, so a client-side QR would mean a second encoder written by hand with nothing comparing it to the one @apifact/qr already ships. It carries no secret the two fields beside it do not: the same bytes, the same response, the same TLS connection, and this response is never logged or persisted. Render it beside the base32 secret, never instead of it -- a QR alone excludes anyone using a desktop password manager."
          }
        }
      }
    }
  },
  "security": [
    {
      "consoleSession": []
    }
  ],
  "paths": {
    "/console/v1/openapi.json": {
      "get": {
        "tags": [
          "Identity"
        ],
        "operationId": "getConsoleOpenApi",
        "summary": "This document",
        "description": "Anonymous, like the machine API's own /api/v2/openapi.json: a client that cannot yet log in still has to be able to read the contract for logging in. It carries no tenant data and no session data — it is the same bytes for every caller.",
        "security": [],
        "responses": {
          "200": {
            "description": "Bundled OpenAPI 3.0.3 document"
          }
        }
      }
    },
    "/console/v1/registrations": {
      "post": {
        "tags": [
          "Identity"
        ],
        "operationId": "registerConsoleUser",
        "summary": "Create an account and its first organization",
        "description": "Answers 202 with the same body whether or not the address was already registered, and pays the same Argon2id cost either way, so neither the response nor its duration is an oracle for who has an account. The registrant becomes the OWNER of a new organization -- the only way to become an OWNER other than being promoted by one. The organization starts with no companies; the registrant attaches one through POST /console/v1/organizations/{organizationId}/companies, which migration 000065 added. This sentence used to say the opposite -- that attaching was deliberately impossible -- and it is the fourth copy of that claim found after the route shipped, which is what a fact repeated in prose costs when nothing compares prose to paths.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleRegistrationRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. If the address was free, a verification link has been issued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleRegistrationAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/email-verifications": {
      "post": {
        "tags": [
          "Identity"
        ],
        "operationId": "verifyConsoleEmail",
        "summary": "Spend an email verification token",
        "description": "Single use. Unknown, expired, already spent and belonging to a disabled account are one outcome and one status code: the consuming UPDATE is the check, so there is nothing to distinguish even if the handler wanted to.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleTokenRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Address verified"
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/sessions": {
      "post": {
        "tags": [
          "Identity"
        ],
        "operationId": "openConsoleSession",
        "summary": "Log in",
        "description": "Sets the session cookie. When the account has TOTP enrolled and no totpCode was supplied -- or the code was replayed -- the answer is 401 MFA_REQUIRED and NO cookie; resend the same body with the code. There is no intermediate ticket, because a ticket is a second session-shaped secret with its own theft story. Every failure below a correct password is one indistinguishable 401 that costs one Argon2id verification, including for an address that was never registered.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleLoginRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session opened; the cookie is in Set-Cookie and nowhere else",
            "headers": {
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "__Host-apf_console=...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=43200"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleSessionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Identity"
        ],
        "operationId": "closeAllConsoleSessions",
        "summary": "Log out everywhere",
        "description": "Revokes every session of the caller, this one included. Needs a live session of its own, so it cannot be aimed at another user.",
        "responses": {
          "204": {
            "description": "All sessions revoked"
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/sessions/current": {
      "delete": {
        "tags": [
          "Identity"
        ],
        "operationId": "closeConsoleSession",
        "summary": "Log out",
        "description": "Revokes this session server-side and clears the cookie. The token is opaque and server-side precisely so this can be instantaneous rather than a matter of waiting for an expiry.",
        "responses": {
          "204": {
            "description": "Session revoked"
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/session": {
      "get": {
        "tags": [
          "Identity"
        ],
        "operationId": "getConsoleSession",
        "summary": "Who am I, and what do I belong to",
        "responses": {
          "200": {
            "description": "The caller and their organizations, with the role in each",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleSessionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/password": {
      "post": {
        "tags": [
          "Identity"
        ],
        "operationId": "changeConsolePassword",
        "summary": "Change the password",
        "description": "Compare-and-swap against the hash just verified, so a change racing another loses instead of silently overwriting it. EVERY session dies, the caller's included: a password change cannot be distinguished from the response to a compromise, and the rule that is right in the second case is the one that applies to both.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleChangePasswordRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Password changed; log in again"
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/mfa/enrolment": {
      "post": {
        "tags": [
          "Identity"
        ],
        "operationId": "beginConsoleMfaEnrolment",
        "summary": "Start TOTP enrolment",
        "responses": {
          "201": {
            "description": "A secret that is stored nowhere until a code proves it works",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleMfaEnrolmentStarted"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/mfa": {
      "post": {
        "tags": [
          "Identity"
        ],
        "operationId": "completeConsoleMfaEnrolment",
        "summary": "Finish TOTP enrolment",
        "description": "The secret is sealed with AES-256-GCM under a versioned KEK, and the step the enrolling code used is recorded with it, so replaying that same code cannot also open a session.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleMfaEnrolmentRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Enrolled"
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Identity"
        ],
        "operationId": "disableConsoleMfa",
        "summary": "Remove the second factor",
        "responses": {
          "204": {
            "description": "Disabled"
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "listConsoleCompanies",
        "summary": "The companies this session can operate",
        "description": "A listing, not an authorisation: it resolves membership across organizations and binds nothing. Selecting one is GET /console/v1/companies/{companyId}, which is where the membership check and the assignment of app.tenant_id happen as one act.",
        "responses": {
          "200": {
            "description": "Every company of every organization the caller belongs to",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCompanyList"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "getConsoleCompany",
        "summary": "Select a company to operate",
        "description": "The tenant binding of ADR 0016 point 5. auth.bind_console_company verifies the membership and sets app.tenant_id in ONE statement inside ONE transaction, and mints a binding token derived from a secret the console database role cannot read; every table the console can read carries a restrictive policy that demands it. Setting app.tenant_id by hand therefore widens nothing. A company in another organization and a company that does not exist both answer 404.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The bound company",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCompanyResponse"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/documents": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "listConsoleDocuments",
        "summary": "Comprobantes with their state",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "documentType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "01",
                "03",
                "07",
                "08"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One keyset page, newest change first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleDocumentPage"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/documents/{documentId}": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "getConsoleDocument",
        "summary": "One comprobante, with the SUNAT verdict and what it means",
        "description": "The response code and description are verbatim from the CDR. The severity/standing/action/guidance block is derived from the catalog in @apifact/sunat at read time and is not stored, so it cannot drift; catalogVersion, by contrast, reports the version recorded on the attempt, because claiming yesterday's rejection was judged by today's catalog would forge the audit trail.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The comprobante",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleDocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/documents/{documentId}/artifacts": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "listConsoleArtifacts",
        "summary": "Everything the platform produced for one comprobante",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Versionless artifacts and versioned PDF renders, in one listing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleArtifactList"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/documents/{documentId}/artifacts/{kind}": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "downloadConsoleArtifact",
        "summary": "Stream one artifact",
        "description": "The bytes come from apps/artifact-worker, which re-verifies the SHA-256 and the byte size of what it reads before any of it reaches the caller. The object key never leaves the server. Use versions/{representationId} as the kind to fetch a specific PDF render.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "kind",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A public artifact kind (signed-xml, submission-zip, cdr-zip, cdr-xml, pdf-a4, pdf-ticket, qr-png), or versions/{representationId} for a specific PDF render."
          }
        ],
        "responses": {
          "200": {
            "description": "The artifact bytes",
            "headers": {
              "Content-Digest": {
                "schema": {
                  "type": "string"
                }
              },
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "409": {
            "description": "ARTIFACT_NOT_READY: it exists but has not been produced yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/credentials": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "listConsoleCredentials",
        "summary": "The API credentials of this company",
        "description": "Any member may read it, VIEWER included. It carries no secret -- there is no column holding one -- and the public prefix it does carry is already reported for every operation by GET /console/v1/companies/{companyId}/activity, so hiding this list would be a rule with no content. Revoked and expired credentials stay in it.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every credential of the bound company, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCredentialList"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Companies"
        ],
        "operationId": "mintConsoleCredential",
        "summary": "Mint an API credential",
        "description": "DEVELOPER and above, which is what ADR 0016 point 7 assigns to that role. The credential can issue comprobantes, so this is the privilege escalation the ADR names and does not pretend otherwise about: the mitigation is that it is recorded. The credential row and its ops.audit_events row are written in one transaction by the SAME function the provisioning API calls, and a DEFERRABLE constraint trigger on auth.api_credentials refuses at COMMIT to admit a credential for an organization-owned company without one -- so an unaudited mint is not a policy violation, it is a failed transaction. THE TOKEN IS IN THE 201 AND NOWHERE ELSE. A scope the caller's own role could not exercise is refused with 403 SCOPE_NOT_GRANTABLE rather than silently dropped.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleMintCredentialRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Minted; the token is in this response and is not recoverable after it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleMintedCredential"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED, or SCOPE_NOT_GRANTABLE when the caller's role may not grant a scope it asked for (certificates:manage needs ADMIN).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/credentials/{credentialId}": {
      "delete": {
        "tags": [
          "Companies"
        ],
        "operationId": "revokeConsoleCredential",
        "summary": "Revoke an API credential",
        "description": "Immediate, not at expiry: auth.lookup_api_credential re-reads revoked_at on every authenticated request, so the next one fails. Same DEVELOPER floor as minting, deliberately and never higher -- revocation is the emergency action, and a system where creating a credential is easier than killing it has the incentives backwards. Unknown, already revoked, and belonging to another company are one 404.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "credentialId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked, as of the moment in the body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCredentialRevoked"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/usage": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "getConsoleUsage",
        "summary": "Plan consumption for this company",
        "description": "A read, and only a read. ADR 0016 point 6 keeps the quota holder on the company and usage.consume_quota is untouched. The period is this company's own plan period, not a window this route picked.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "metric",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 60,
              "default": "documents.accepted"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Limit and consumption for the current period",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleUsageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/activity": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "getConsoleActivity",
        "summary": "The request and error log",
        "description": "The read that exists so a rejected comprobante does not become an email to support. One entry per SUNAT attempt -- retries are never collapsed -- plus operations that never reached SUNAT at all, each with the verbatim response code and description, the transport classification, and the PUBLIC prefix of the credential that started it. The free-form operations.result jsonb is deliberately NOT published: nothing bounds what a future workflow writes into it.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "documentId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recent attempts and operations, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleActivityResponse"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/organizations/{organizationId}/members": {
      "get": {
        "tags": [
          "Organizations"
        ],
        "operationId": "listConsoleMembers",
        "summary": "Who is in this organization",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Members, highest role first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleMemberList"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/organizations/{organizationId}/members/{userId}": {
      "patch": {
        "tags": [
          "Organizations"
        ],
        "operationId": "setConsoleMemberRole",
        "summary": "Change a member's role",
        "description": "OWNER only, and the last OWNER can be neither demoted nor removed. The affected member's sessions are revoked -- theirs alone, since a role change concerns one person and logging the whole team out would turn administration into an outage.",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleMemberRoleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new role",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleMemberRoleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Organizations"
        ],
        "operationId": "removeConsoleMember",
        "summary": "Remove a member",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removed; memberRole is null",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleMemberRoleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/certificates": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "listConsoleCertificates",
        "summary": "The certificate versions this company has enrolled",
        "description": "ADMIN and above. Status and validity only: no storage location and no secret, because this route reads through the same repository the machine surface uses and that repository cannot read an envelope's location at all.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Enrolled versions, newest first, with the latest activation attempt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCertificateList"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Companies"
        ],
        "operationId": "enrolConsoleCertificate",
        "summary": "Enrol a new certificate version",
        "description": "ADMIN and above, which is the floor ADR 0016 point 7 sets for companies and the one 000060 already applies to minting a credential that carries certificates:manage. Takes the four secrets SUNAT needs: the PKCS#12, its password, and the SOL user and password that authenticate the submission. None of them touches a database connection — they cross the signing service binding and are sealed there. The result is a DRAFT that signs nothing; whatever certificate is signing today keeps signing until an activation probe is accepted by SUNAT.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleEnrolCertificateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A DRAFT version was sealed and recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCertificateEnrolled"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/companies/{companyId}/certificates/{configurationId}/activation": {
      "get": {
        "tags": [
          "Companies"
        ],
        "operationId": "getConsoleCertificateActivation",
        "summary": "How the activation probe went",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "configurationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The attempt, and SUNAT's verdict if it has one yet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCertificateActivation"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Companies"
        ],
        "operationId": "activateConsoleCertificate",
        "summary": "Ask SUNAT to prove this version",
        "description": "Answers 202 and nothing is switched yet. A DRAFT reaches ACTIVE only after this platform has signed a factura on the reserved series F000 with that certificate and SUNAT beta has accepted it (000052) — proof of control checked by the party that can check it. PRODUCTION is refused, because a production certificate cannot be proved against beta and issuing a real comprobante to prove it is not the platform's call. This route takes no Idempotency-Key: the key is derived from the version, so a double-click replays instead of probing twice.",
        "parameters": [
          {
            "name": "companyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "configurationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "A probe was started; the version stays DRAFT until it is accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCertificateActivationStarted"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/organizations/{organizationId}/companies": {
      "post": {
        "tags": [
          "Organizations"
        ],
        "operationId": "createConsoleCompany",
        "summary": "Register a company under this organization",
        "description": "ADMIN and above, which is ADR 0016 point 7's assignment of companies rather than this route's opinion. Nothing here proves the caller controls the RUC and nothing needs to: the claim confers nothing until a certificate this platform signed with has been accepted by SUNAT, which is proof of control checked by the party that can perform it. What the alta does guarantee is attribution -- it writes an ops.audit_events row naming the person, in the same transaction as the company -- so a squatted RUC is an operator action with evidence rather than an argument between two customers. Every refusal about WHO the caller is answers 409 MEMBERSHIP_CHANGE_REFUSED indistinguishably; only a RUC already registered answers something specific, and it says nothing about whose it is.",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleCreateCompanyRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Company registered and attributed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleCompanyCreated"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/organizations/{organizationId}/credentials": {
      "get": {
        "tags": [
          "Organizations"
        ],
        "operationId": "listConsoleOrganizationCredentials",
        "summary": "The provisioning credentials of this organization",
        "description": "OWNER, and NOT VIEWER as the company credential listing is. That one is VIEWER because GET /console/v1/companies/{companyId}/activity already publishes every company credential's public prefix to every VIEWER, so hiding the list would be a rule with no content; nothing publishes an organization credential's prefix, because it issues nothing and so reaches no activity row. What is left is that this listing is the input to the revocation decision -- you revoke the row you are looking at -- and a list readable by somebody who cannot act on it splits an emergency across two people. It carries no secret: only a SHA-256 is stored. Revoked and expired credentials stay in it.",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Every organization credential, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleOrganizationCredentialList"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Organizations"
        ],
        "operationId": "mintConsoleOrganizationCredential",
        "summary": "Mint an organization credential",
        "description": "OWNER, and an enrolled second factor. This is the credential a SaaS puts in a server to register its own client companies by API. THE FLOOR IS NOT ADMIN, and not by symmetry with anything: every other act an ADMIN performs lands inside their own organization, whereas companies:manage can register a company under ANY RUC in Peru, and core.companies.ruc is unique platform-wide, so claiming one DENIES it to whoever controls it -- a third party with no account here. SUNAT publishes no ownership oracle, so migration 000053's answer is attribution rather than prevention: every act writes an ops.audit_events row in the same transaction. A control whose whole mechanism is 'we can say who did it' belongs to the rank that can be held answerable. THE SECOND FACTOR IS CHECKED IN SQL, on auth.users.mfa_enrolled_at, because the failure this act invites is a stolen session -- which is by construction a caller of the correct rank, and would make the audit row name somebody who did nothing. Enrolment is self-service, so this strands nobody. THE TOKEN IS IN THE 201 AND NOWHERE ELSE.",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleMintOrganizationCredentialRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Minted; the token is in this response and is not recoverable after it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleMintedOrganizationCredential"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED, or SECOND_FACTOR_REQUIRED when the acting OWNER has no TOTP enrolled. The second is reachable only by somebody already confirmed to be an OWNER of this organization, so it discloses nothing they did not know about their own account -- and it is the only thing they can act on, which is why it is not fused into the silent 409 below.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "409": {
            "description": "MEMBERSHIP_CHANGE_REFUSED -- the organization may not exist, may not be yours, may be suspended, or your role may be below OWNER. The four are deliberately indistinguishable: the SQL returns zero rows for all of them, and separating them here would hand out an oracle for which organization ids are real.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/organizations/{organizationId}/credentials/{credentialId}": {
      "delete": {
        "tags": [
          "Organizations"
        ],
        "operationId": "revokeConsoleOrganizationCredential",
        "summary": "Revoke an organization credential",
        "description": "Immediate, not at expiry: auth.assert_organization_credential re-reads revoked_at on every provisioning statement. Same OWNER floor as minting, never higher, AND DELIBERATELY WITHOUT THE SECOND FACTOR the mint requires. Revocation is the emergency action -- it is what somebody does at 2am with a secret in a public repository -- and the person reaching for the kill switch is the person whose phone may be the thing that was lost. Minting creates risk and carries the friction; revoking removes risk and carries none. Unknown, already revoked, and belonging to another organization are one 404.",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "credentialId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked, as of the moment in the body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleOrganizationCredentialRevoked"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/organizations/{organizationId}/invitations": {
      "get": {
        "tags": [
          "Organizations"
        ],
        "operationId": "listConsoleInvitations",
        "summary": "Invitations sent and not yet spent",
        "description": "ADMIN and above, unlike the member list: a pending invitation names an address that belongs to nobody here yet.",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Live invitations",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleInvitationList"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Organizations"
        ],
        "operationId": "inviteConsoleMember",
        "summary": "Invite somebody",
        "description": "ADMIN and above, and nobody may invite above their own rank: an ADMIN who could mint an OWNER is an ADMIN who can promote themselves through a second account. The invitation is bound to the address it names, so a forwarded link is worth nothing to anybody else.",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleInvitationRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invitation issued; the token is in this response and nowhere else",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleInvitationCreated"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/organizations/{organizationId}/invitations/{invitationId}": {
      "delete": {
        "tags": [
          "Organizations"
        ],
        "operationId": "revokeConsoleInvitation",
        "summary": "Withdraw an invitation",
        "description": "An invitation lives a week. Without this, an invitation sent to a mistyped address is live for all of it.",
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "invitationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked"
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    },
    "/console/v1/invitations/acceptance": {
      "post": {
        "tags": [
          "Organizations"
        ],
        "operationId": "acceptConsoleInvitation",
        "summary": "Accept an invitation",
        "description": "Requires a live session whose verified address is the one the invitation was sent to. Accepting with a different account would turn a leaked link into a way into someone else's organization. An invitation for somebody who is already a member is spent without changing the role they already have.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConsoleTokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Joined",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleInvitationAccepted"
                }
              }
            }
          },
          "400": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "401": {
            "description": "No usable session cookie, or MFA_REQUIRED on the login route. A machine credential in an Authorization header reaches this too: console routes never read that header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "403": {
            "description": "CSRF_ORIGIN_REJECTED. Every unsafe method requires an Origin header naming a configured console origin; a deployment with none configured refuses them all.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "404": {
            "description": "The resource does not exist, or is not visible to this session. The two are deliberately indistinguishable: a company in another organization answers exactly what an invented uuid answers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "405": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "413": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "415": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "422": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "500": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          },
          "503": {
            "description": "Stable error envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConsoleError"
                }
              }
            }
          }
        }
      }
    }
  }
}
