{
  "openapi": "3.1.0",
  "info": {
    "title": "Veyns identity and approval API",
    "version": "0.7.0",
    "description": "Regional identity and approval APIs for the unified Veyns website. Each region has its own issuer, accounts and Palm companion. Backend credentials stay on application servers. Decision acknowledgement is separate from business execution."
  },
  "servers": [
    {
      "url": "https://ae.id.veyns.io",
      "description": "United Arab Emirates regional issuer; availability is published in https://id.veyns.io/regions.json"
    },
    {
      "url": "https://sg.id.veyns.io",
      "description": "Singapore regional issuer; availability is published in https://id.veyns.io/regions.json"
    },
    {
      "url": "https://gb.id.veyns.io",
      "description": "United Kingdom regional issuer; availability is published in https://id.veyns.io/regions.json"
    }
  ],
  "paths": {
    "/v1/authorize/prepare": {
      "post": {
        "summary": "Prepare a PKCE request without putting action details in a URL",
        "responses": {
          "201": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authorization_url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "expires_in": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Signup country, location consent, region or first-party client is not allowed."
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreparedAuthorization"
              }
            }
          }
        },
        "description": "The regional issuer validates PKCE and client registration. In unified mode authorization_url points to the common website; its region and request reference are in the URL fragment. Signup fields are accepted only for the first-party veyns-console client. They never authorize a session without passkey verification."
      }
    },
    "/v1/approvals": {
      "post": {
        "summary": "Request palm approval for an application-linked subject",
        "responses": {
          "201": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Approval"
                }
              }
            }
          },
          "400": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Setup required (scanner_required or palm_not_linked), or idempotency conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "applicationBackend": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApprovalRequest"
              }
            }
          }
        },
        "description": " New requests require an admitted account, an active passkey, its verified palm identity and at least one active verified scanner. A 409 scanner_required response means reconnect and verify a scanner before creating a new approval. No request is created for this error. Identical idempotent retries still return an existing request after scanner removal; this does not grant approval."
      }
    },
    "/v1/approvals/{request_id}": {
      "get": {
        "summary": "Read the durable decision",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Approval"
                }
              }
            }
          },
          "400": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "applicationBackend": []
          }
        ]
      },
      "parameters": [
        {
          "name": "request_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ]
    },
    "/v1/approvals/{request_id}/cancel": {
      "post": {
        "summary": "Cancel a pending request, including an active verification",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Approval"
                }
              }
            }
          },
          "400": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "applicationBackend": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      },
      "parameters": [
        {
          "name": "request_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ]
    },
    "/v1/approvals/{request_id}/ack": {
      "post": {
        "summary": "Acknowledge delivery using a stable business operation id",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "applicationBackend": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Acknowledgement"
              }
            }
          }
        }
      },
      "parameters": [
        {
          "name": "request_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ]
    },
    "/v1/actions/consume": {
      "post": {
        "summary": "Acknowledge an earlier browser-action receipt",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "applicationBackend": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jti",
                  "action_digest",
                  "operation_id"
                ],
                "properties": {
                  "jti": {
                    "type": "string"
                  },
                  "action_digest": {
                    "type": "string"
                  },
                  "operation_id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/openid-configuration": {
      "get": {
        "summary": "Discover the issuer and its OAuth endpoints",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/jwks.json": {
      "get": {
        "summary": "Read the issuer verification keys",
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/v1/account/palm/pairing": {
      "post": {
        "summary": "Create a one-time scanner connection QR for the signed-in account",
        "description": "First-party account UI only. Requires recent sign-in, an active passkey, palm admission and same-origin POST. QR routing grants no palm consent. The QR is consumable for 600 seconds; verification starts a separate 300-second deadline. Existing pairing_code consumers remain compatible. Identical signed pairing retries return the original request while the code is valid.",
        "security": [
          {
            "accountSession": []
          }
        ],
        "responses": {
          "201": {
            "description": "Private connection QR; expires in 600 seconds. Never log or send it to a third-party QR renderer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "pairing_code",
                    "qr_uri",
                    "issuer",
                    "expires_in",
                    "setup_id",
                    "expires_at",
                    "server_time"
                  ],
                  "properties": {
                    "pairing_code": {
                      "type": "string"
                    },
                    "qr_uri": {
                      "type": "string",
                      "format": "uri",
                      "description": "Fixed issuer /palm#pair= followed by 20 uppercase hexadecimal characters."
                    },
                    "issuer": {
                      "type": "string",
                      "format": "uri"
                    },
                    "expires_in": {
                      "type": "integer",
                      "const": 600
                    },
                    "setup_id": {
                      "type": "string",
                      "description": "Opaque, account-scoped setup status handle. Never use as an authentication credential."
                    },
                    "expires_at": {
                      "type": "integer",
                      "description": "QR expiry as Unix seconds."
                    },
                    "server_time": {
                      "type": "integer",
                      "description": "Current server time as Unix seconds for countdowns."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Recent account sign-in required"
          },
          "403": {
            "description": "Palm access disabled or active passkey required"
          }
        }
      }
    },
    "/v1/txn/{transaction_id}/palm": {
      "post": {
        "summary": "Begin palm sign-in for an existing PKCE ceremony",
        "description": "First-party Veyns ceremony UI. Account routing is resolved from server-issued cookies only, never from a submitted account ID. This endpoint cannot authenticate the caller.",
        "parameters": [
          {
            "name": "transaction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "other_scanner": {
                    "type": "boolean",
                    "description": "Cancel the pending prompt and offer a new QR. Rejected once verification begins."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bound palm request. Older code entry clients remain compatible.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "request_id": {
                      "type": "string"
                    },
                    "request_code": {
                      "type": "string"
                    },
                    "delivery": {
                      "type": "string",
                      "enum": [
                        "scanner",
                        "qr"
                      ]
                    },
                    "qr_uri": {
                      "type": "string",
                      "format": "uri",
                      "description": "Fixed issuer /palm#login= plus the one-time code; display only for QR delivery."
                    },
                    "expires_at": {
                      "type": "integer"
                    },
                    "status": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unknown or closed ceremony"
          },
          "409": {
            "description": "Previous request is already being verified"
          }
        }
      }
    },
    "/v1/txn/{transaction_id}/result": {
      "get": {
        "summary": "Check a palm sign-in ceremony",
        "description": "First-party ceremony polling with the original opaque transaction reference. Pending delivery identifies whether this browser still needs a QR scan or a connected scanner can review the request. It grants no session or approval.",
        "parameters": [
          {
            "name": "transaction_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current ceremony state. Approved responses retain the existing bound authorization-code delivery fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string"
                    },
                    "delivery": {
                      "type": "string",
                      "enum": [
                        "qr",
                        "scanner"
                      ],
                      "description": "Present before approval; changes to scanner when a QR request is claimed."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown palm ceremony"
          },
          "410": {
            "description": "Approved code expired"
          }
        }
      }
    },
    "/logout": {
      "get": {
        "summary": "End the current Veyns browser session",
        "description": "Standalone deployments retain legacy logout behavior. Unified regional deployments redirect to the common account page without changing a session; use POST /v1/account/logout.",
        "parameters": [
          {
            "name": "forget_scanner",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Explicitly forget this browser scanner preference as well as signing out."
          }
        ],
        "responses": {
          "200": {
            "description": "Signed out; authentication cookie cleared."
          },
          "302": {
            "description": "Signed out and redirected to an already registered application origin."
          }
        }
      }
    },
    "/v1/account/palm/pairing/{setup_id}": {
      "get": {
        "summary": "Check this account\u2019s scanner setup stage and deadline",
        "description": "First-party account UI only. Setup status never grants consent or exposes a capture challenge. Poll every 2.5 seconds; stop on a terminal state. Pairing expiry does not shorten an already-started verification. Removed or superseded scanner setup reports cancelled. Unknown or another account\u2019s handle returns 404. Status is retained for 20 minutes from QR creation; the QR remains consumable for only 600 seconds.",
        "security": [
          {
            "accountSession": []
          }
        ],
        "parameters": [
          {
            "name": "setup_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current setup stage",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PalmSetupStatus"
                }
              }
            }
          },
          "401": {
            "description": "Account sign-in required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown setup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Polling limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/devices/inbox": {
      "get": {
        "tags": [
          "First-party scanner"
        ],
        "summary": "Read approvals and the current device setup state",
        "security": [
          {
            "deviceId": [],
            "deviceTime": [],
            "deviceNonce": [],
            "deviceSignature": []
          }
        ],
        "description": "Signed device access only. Older apps may ignore setup. Setup includes closed link requests so recovery remains available when the pending inbox is empty.",
        "responses": {
          "200": {
            "description": "Pending approvals plus setup state",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "requests",
                    "setup"
                  ],
                  "properties": {
                    "requests": {
                      "type": "array",
                      "maxItems": 50,
                      "items": {
                        "type": "object"
                      }
                    },
                    "setup": {
                      "$ref": "#/components/schemas/DeviceSetup"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid device proof",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account or passkey is not eligible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "The signed request nonce was already used; send a new proof",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/devices/requests/{request_id}/retry-link": {
      "post": {
        "tags": [
          "First-party scanner"
        ],
        "summary": "Explicitly retry a failed or expired account-link verification",
        "description": "No biometric submission or enrollment is performed. Only the current link on the authenticated device/account is eligible. The predecessor request is the durable idempotency key; retries return its same successor. Approved, denied, cancelled, pending, verifying, superseded and application/login requests are refused. Fresh consent and a new capture are required. Link captures are limited to five per account in a 300-second window, across reconnections. Retry creation also has a separate limit of five per account per 300-second window. Replaying an existing predecessor does not create a request or consume another retry. Use the exact path, no query string, and no cookie or Authorization header.",
        "security": [
          {
            "deviceId": [],
            "deviceTime": [],
            "deviceNonce": [],
            "deviceSignature": []
          }
        ],
        "parameters": [
          {
            "name": "request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "maxProperties": 0
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New successor, or the current state of the previously created successor. Creating a retry does not verify the account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceLinkRequest"
                }
              }
            }
          },
          "400": {
            "description": "Invalid retry body, query string or conflicting credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid device proof",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Account or passkey is not eligible",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request does not belong to this device/account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Closed/superseded request or unresolved enrollment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Wait before another attempt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Service temporarily busy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/region": {
      "get": {
        "summary": "Public regional signup readiness",
        "security": [],
        "responses": {
          "200": {
            "description": "No-store admission status; includes no user or gallery counts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "region",
                    "issuer",
                    "web_origin",
                    "rp_id",
                    "accepting_signups",
                    "signup_countries"
                  ],
                  "properties": {
                    "region": {
                      "enum": [
                        "ae",
                        "sg",
                        "gb"
                      ]
                    },
                    "issuer": {
                      "type": "string",
                      "format": "uri"
                    },
                    "web_origin": {
                      "type": "string",
                      "format": "uri"
                    },
                    "rp_id": {
                      "type": "string"
                    },
                    "accepting_signups": {
                      "type": "boolean"
                    },
                    "signup_countries": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "pattern": "^[A-Z]{2}$"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Probe rate limit reached."
          }
        }
      }
    },
    "/v1/account/logout": {
      "post": {
        "summary": "End the selected regional browser session",
        "security": [
          {
            "accountSession": []
          }
        ],
        "description": "Requires the configured shared web Origin. Clears the HttpOnly regional cookie. Does not delete account or enrollment.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "forget_scanner": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session cleared; signed_out is true."
          },
          "403": {
            "description": "Origin refused."
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "summary": "Read the signed-in regional account",
        "security": [
          {
            "accountSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Current account including home_region and regional issuer.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "account_id": {
                      "type": "string"
                    },
                    "home_region": {
                      "enum": [
                        "ae",
                        "sg",
                        "gb",
                        null
                      ]
                    },
                    "issuer": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Regional session missing or expired."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "applicationBackend": {
        "type": "http",
        "scheme": "basic",
        "description": "Registered client id and server-side application secret."
      },
      "accountSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-veyns_sid",
        "description": "Unified production host-only Secure/HttpOnly regional session, accepted only with the exact common web Origin for mutations. Standalone/HTTP development uses veyns_sid. Never an application credential."
      },
      "deviceId": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Veyns-Device",
        "description": "Part of the registered device proof. All four device headers are required together; the signature binds issuer, method, exact route, body digest, device, timestamp and nonce."
      },
      "deviceTime": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Veyns-Time",
        "description": "Part of the registered device proof. All four device headers are required together; the signature binds issuer, method, exact route, body digest, device, timestamp and nonce."
      },
      "deviceNonce": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Veyns-Nonce",
        "description": "Part of the registered device proof. All four device headers are required together; the signature binds issuer, method, exact route, body digest, device, timestamp and nonce."
      },
      "deviceSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Veyns-Signature",
        "description": "Part of the registered device proof. All four device headers are required together; the signature binds issuer, method, exact route, body digest, device, timestamp and nonce."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "error_description": {
            "type": "string"
          }
        }
      },
      "Action": {
        "type": "object",
        "required": [
          "statement"
        ],
        "additionalProperties": false,
        "properties": {
          "statement": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "details": {
            "type": [
              "object",
              "null"
            ]
          }
        }
      },
      "Approval": {
        "type": "object",
        "required": [
          "request_id",
          "status",
          "challenge",
          "required_method",
          "expires_at"
        ],
        "properties": {
          "request_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "verifying",
              "approved",
              "denied",
              "cancelled",
              "expired",
              "failed"
            ]
          },
          "challenge": {
            "type": "string"
          },
          "required_method": {
            "const": "palm"
          },
          "application": {
            "type": "string"
          },
          "kind": {
            "const": "approval"
          },
          "action": {
            "type": "object",
            "properties": {
              "statement": {
                "type": "string"
              },
              "details": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "digest": {
                "type": "string"
              }
            },
            "required": [
              "statement",
              "digest"
            ]
          },
          "created_at": {
            "type": "integer"
          },
          "expires_at": {
            "type": "integer"
          },
          "decision": {
            "type": "string"
          },
          "decision_id": {
            "type": "string"
          },
          "acknowledged": {
            "type": "boolean"
          },
          "approval_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "ApprovalRequest": {
        "type": "object",
        "required": [
          "subject",
          "idempotency_key",
          "action"
        ],
        "additionalProperties": false,
        "properties": {
          "subject": {
            "type": "string"
          },
          "idempotency_key": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128
          },
          "expires_in": {
            "type": "integer",
            "minimum": 30,
            "maximum": 300,
            "default": 300
          },
          "action": {
            "$ref": "#/components/schemas/Action"
          }
        }
      },
      "Acknowledgement": {
        "type": "object",
        "required": [
          "decision_id",
          "operation_id"
        ],
        "additionalProperties": false,
        "properties": {
          "decision_id": {
            "type": "string"
          },
          "operation_id": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128
          }
        }
      },
      "PreparedAuthorization": {
        "type": "object",
        "required": [
          "response_type",
          "client_id",
          "redirect_uri",
          "scope",
          "code_challenge",
          "code_challenge_method"
        ],
        "properties": {
          "response_type": {
            "const": "code"
          },
          "response_mode": {
            "enum": [
              "query",
              "web_message"
            ]
          },
          "client_id": {
            "type": "string"
          },
          "redirect_uri": {
            "type": "string",
            "format": "uri"
          },
          "scope": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "nonce": {
            "type": "string"
          },
          "code_challenge": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "code_challenge_method": {
            "const": "S256"
          },
          "intent": {
            "enum": [
              "login",
              "presence",
              "action"
            ]
          },
          "required_method": {
            "enum": [
              "browser",
              "palm"
            ]
          },
          "action": {
            "$ref": "#/components/schemas/Action"
          },
          "region": {
            "type": "string",
            "enum": [
              "ae",
              "sg",
              "gb"
            ],
            "description": "First-party signup only. Must match the receiving regional issuer."
          },
          "signup_country": {
            "type": "string",
            "pattern": "^[A-Z]{2}$",
            "description": "Declared country, enforced against the region signup allowlist."
          },
          "location_consent": {
            "type": "boolean",
            "const": true,
            "description": "Required for first-party new account creation."
          },
          "signup_attempt": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "Durable random first-party signup attempt. Retain the same value and region after uncertain outcomes."
          }
        }
      },
      "PalmSetupStatus": {
        "type": "object",
        "required": [
          "stage",
          "status",
          "expires_at",
          "server_time"
        ],
        "properties": {
          "stage": {
            "type": "string",
            "enum": [
              "pairing",
              "verification"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "verifying",
              "approved",
              "denied",
              "cancelled",
              "expired",
              "failed"
            ]
          },
          "expires_at": {
            "type": "integer",
            "description": "Deadline of the current stage, as Unix seconds."
          },
          "server_time": {
            "type": "integer"
          },
          "enrollment_status": {
            "type": "string",
            "enum": [
              "unknown",
              "pending",
              "acknowledged",
              "existing"
            ],
            "description": "Account/device/terminal/signing-key scoped delivery hint. Acknowledged is not account verification; existing does not establish ownership."
          },
          "retry_allowed": {
            "type": "boolean"
          }
        }
      },
      "AccountId": {
        "type": "string",
        "pattern": "^acct_[A-Za-z0-9_-]{12}$",
        "description": "Current internal account handle used in staff/account tooling, generated from 9 cryptographically random bytes. Treat as opaque. This is NOT an application subject; applications must use the pairwise sub issued for their client."
      },
      "DeviceLinkRequest": {
        "type": "object",
        "required": [
          "request_id",
          "kind",
          "application",
          "challenge",
          "status",
          "expires_at",
          "required_method"
        ],
        "properties": {
          "request_id": {
            "type": "string"
          },
          "kind": {
            "const": "link"
          },
          "application": {
            "type": "string"
          },
          "challenge": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "verifying",
              "approved",
              "denied",
              "cancelled",
              "expired",
              "failed"
            ]
          },
          "expires_at": {
            "type": "integer"
          },
          "required_method": {
            "const": "palm"
          }
        }
      },
      "DeviceSetup": {
        "type": "object",
        "required": [
          "version",
          "enrollment_status",
          "verified",
          "request",
          "retry_allowed"
        ],
        "properties": {
          "version": {
            "const": 1
          },
          "enrollment_status": {
            "type": "string",
            "enum": [
              "unknown",
              "pending",
              "acknowledged",
              "existing"
            ],
            "description": "Account/device/terminal/signing-key scoped delivery hint. Acknowledged is not account verification; existing does not establish ownership."
          },
          "verified": {
            "type": "boolean",
            "description": "True only after the account palm binding and active device verification agree."
          },
          "request": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/DeviceLinkRequest"
              },
              {
                "type": "null"
              }
            ]
          },
          "retry_allowed": {
            "type": "boolean",
            "description": "Explicit retry is permitted for the current failed/expired link only. It does not authorize a capture."
          }
        }
      }
    }
  }
}
