{ "openapi": "3.1.0", "info": { "title": "BKey API", "description": "Biometric approval infrastructure for AI agents — OAuth 2.1 + CIBA", "version": "1.0.0", "contact": { "name": "BKey", "url": "https://bkey.id", "email": "dev@bkey.id" }, "license": { "name": "Apache-2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0" } }, "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "EdDSA-signed JWT obtained via OAuth 2.1 client_credentials or CIBA" }, "merchantApiKey": { "type": "http", "scheme": "bearer", "bearerFormat": "mk_live_XXX or mk_test_XXX", "description": "Merchant API key issued during merchant onboarding. Distinct from OAuth JWT." } }, "schemas": {} }, "paths": { "/oauth/jwks": { "get": { "summary": "Get JWKS", "tags": [ "OAuth" ], "description": "Returns the JSON Web Key Set for verifying BKey-issued JWTs (EdDSA / Ed25519).", "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "keys": { "type": "array", "items": { "type": "object", "properties": { "kty": { "type": "string", "description": "Key type (e.g., \"OKP\" for Ed25519)" }, "crv": { "type": "string", "description": "Curve name (e.g., \"Ed25519\")" }, "x": { "type": "string", "description": "Base64url-encoded public key" }, "use": { "type": "string" }, "alg": { "type": "string" }, "kid": { "type": "string" } }, "required": [ "kty", "crv", "x" ], "additionalProperties": false } } }, "required": [ "keys" ], "additionalProperties": false } } } } } } }, "/oauth/token": { "post": { "summary": "Token Endpoint", "tags": [ "OAuth" ], "description": "RFC 6749 token endpoint. Supports grant types: client_credentials, refresh_token, urn:ietf:params:oauth:grant-type:device_code, urn:openid:params:grant-type:ciba. Request body must be application/x-www-form-urlencoded.", "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "access_token": { "type": "string", "description": "EdDSA-signed JWT" }, "token_type": { "type": "string", "enum": [ "Bearer" ] }, "expires_in": { "type": "integer", "description": "Token lifetime in seconds" }, "scope": { "type": "string", "description": "Space-separated list of granted scopes" }, "refresh_token": { "type": "string" }, "id_token": { "type": "string", "description": "OIDC ID token (if openid scope was granted)" } }, "required": [ "access_token", "token_type", "expires_in" ], "additionalProperties": false } } } }, "400": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "description": "Error code (e.g., invalid_grant, unauthorized_client)" }, "error_description": { "type": "string" }, "error_uri": { "type": "string", "format": "uri" } }, "required": [ "error" ], "additionalProperties": false } } } }, "401": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "description": "Error code (e.g., invalid_grant, unauthorized_client)" }, "error_description": { "type": "string" }, "error_uri": { "type": "string", "format": "uri" } }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/oauth/bc-authorize": { "post": { "summary": "CIBA Backchannel Authorize", "tags": [ "OAuth" ], "description": "Initiate a CIBA backchannel authentication request. The user receives a push notification to approve on their mobile device; poll POST /oauth/token with grant_type urn:openid:params:grant-type:ciba to retrieve the approval token.", "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "auth_req_id": { "type": "string", "description": "CIBA authentication request ID" }, "expires_in": { "type": "integer", "description": "auth_req_id lifetime in seconds" }, "interval": { "type": "integer", "description": "Minimum polling interval in seconds" } }, "required": [ "auth_req_id", "expires_in" ], "additionalProperties": false } } } }, "400": { "description": "invalid_request / invalid_scope", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "description": "Error code (e.g., invalid_grant, unauthorized_client)" }, "error_description": { "type": "string" }, "error_uri": { "type": "string", "format": "uri" } }, "required": [ "error" ], "additionalProperties": false, "description": "invalid_request / invalid_scope" } } } }, "401": { "description": "invalid_client / unauthorized_client", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "description": "Error code (e.g., invalid_grant, unauthorized_client)" }, "error_description": { "type": "string" }, "error_uri": { "type": "string", "format": "uri" } }, "required": [ "error" ], "additionalProperties": false, "description": "invalid_client / unauthorized_client" } } } } } } }, "/oauth/revoke": { "post": { "summary": "Revoke Token", "tags": [ "OAuth" ], "description": "RFC 7009 token revocation. Revokes an access or refresh token. Always returns 200 (per spec) even if the token is unknown, to prevent token enumeration.", "responses": { "200": { "description": "Empty body (RFC 7009)", "content": { "application/json": { "schema": { "type": "object", "properties": {}, "additionalProperties": false, "description": "Empty body (RFC 7009)" } } } }, "400": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "description": "Error code (e.g., invalid_grant, unauthorized_client)" }, "error_description": { "type": "string" }, "error_uri": { "type": "string", "format": "uri" } }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/oauth/device/code": { "post": { "summary": "Device Authorization", "tags": [ "OAuth" ], "description": "RFC 8628 device authorization request. Returns a user_code and verification_uri that the user visits on another device to approve. Poll POST /oauth/token with grant_type urn:ietf:params:oauth:grant-type:device_code to retrieve the token.", "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "device_code": { "type": "string" }, "user_code": { "type": "string" }, "verification_uri": { "type": "string", "format": "uri" }, "verification_uri_complete": { "type": "string", "format": "uri" }, "expires_in": { "type": "integer", "description": "Device code lifetime in seconds" }, "interval": { "type": "integer", "description": "Minimum polling interval in seconds" } }, "required": [ "device_code", "user_code", "verification_uri", "expires_in", "interval" ], "additionalProperties": false } } } }, "400": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "description": "Error code (e.g., invalid_grant, unauthorized_client)" }, "error_description": { "type": "string" }, "error_uri": { "type": "string", "format": "uri" } }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/userinfo": { "get": { "summary": "Get UserInfo", "tags": [ "OAuth" ], "description": "OIDC UserInfo. Returns the authenticated subject (user DID) and granted scopes for the bearer token. Use this to verify a CIBA approval token and identify which user approved the action.", "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "sub": { "type": "string", "description": "Subject identifier — user DID or client ID" }, "scope": { "type": "string", "description": "Space-separated granted scopes" }, "client_id": { "type": "string", "description": "OAuth client ID (for client_credentials tokens)" } }, "required": [ "sub", "scope" ], "additionalProperties": false } } } }, "401": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "string", "description": "Error code (e.g., invalid_grant, unauthorized_client)" }, "error_description": { "type": "string" }, "error_uri": { "type": "string", "format": "uri" } }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/.well-known/openid-configuration": { "get": { "summary": "OIDC Discovery", "tags": [ "OAuth" ], "description": "OpenID Connect discovery document. Lists all supported endpoints, grant types, scopes, and signing algorithms.", "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "issuer": { "type": "string", "format": "uri" }, "userinfo_endpoint": { "type": "string", "format": "uri" }, "jwks_uri": { "type": "string", "format": "uri" }, "token_endpoint": { "type": "string", "format": "uri" }, "device_authorization_endpoint": { "type": "string", "format": "uri" }, "backchannel_authentication_endpoint": { "type": "string", "format": "uri" }, "revocation_endpoint": { "type": "string", "format": "uri" }, "grant_types_supported": { "type": "array", "items": { "type": "string" } }, "backchannel_token_delivery_modes_supported": { "type": "array", "items": { "type": "string" } }, "token_endpoint_auth_methods_supported": { "type": "array", "items": { "type": "string" } }, "scopes_supported": { "type": "array", "items": { "type": "string" } }, "response_types_supported": { "type": "array", "items": { "type": "string" } }, "subject_types_supported": { "type": "array", "items": { "type": "string" } }, "id_token_signing_alg_values_supported": { "type": "array", "items": { "type": "string" } } }, "required": [ "issuer", "userinfo_endpoint", "jwks_uri", "token_endpoint", "device_authorization_endpoint", "backchannel_authentication_endpoint", "revocation_endpoint", "grant_types_supported", "backchannel_token_delivery_modes_supported", "token_endpoint_auth_methods_supported", "scopes_supported", "response_types_supported", "subject_types_supported", "id_token_signing_alg_values_supported" ], "additionalProperties": false } } } } } } }, "/v1/vault/keys": { "get": { "summary": "List Vault Keys", "tags": [ "Vault" ], "description": "Fetches the mobile device's X25519 public key for end-to-end encrypting vault payloads. Requires the vault:store scope. The mobile app must have registered a key first.", "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "publicKey": { "type": "string", "description": "Base64-encoded X25519 public key of the mobile device" }, "keyId": { "type": "string", "description": "Optional identifier for the public key" } }, "required": [ "success", "publicKey" ], "additionalProperties": false } } } }, "401": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "403": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "404": { "description": "No vault public key registered yet", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false, "description": "No vault public key registered yet" } } } } } } }, "/v1/vault/access": { "post": { "summary": "Request Vault Access", "tags": [ "Vault" ], "description": "Agent requests access to a vault item by name. Sends a push notification to the user for biometric approval. Poll GET /v1/vault/access/{id} for the status + decrypted payload.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "itemName": { "type": "string", "minLength": 1, "maxLength": 128 }, "fieldPath": { "type": "string", "minLength": 1, "maxLength": 64 }, "purpose": { "type": "string", "minLength": 1, "maxLength": 512 }, "ephemeralPublicKey": { "type": "string", "minLength": 1, "maxLength": 256 }, "expiresInSecs": { "type": "integer", "minimum": 30, "maximum": 600, "default": 120 } }, "required": [ "itemName", "fieldPath", "purpose", "ephemeralPublicKey" ], "additionalProperties": false } } } }, "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "description": "Access request ID — use this to poll status" }, "status": { "type": "string", "description": "Initial status — typically \"pending\"" }, "challengeHex": { "type": "string", "description": "Challenge the mobile device signs on approval" }, "ephemeralPublicKey": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "status", "challengeHex", "ephemeralPublicKey", "expiresAt", "createdAt" ], "additionalProperties": false } } } }, "400": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "401": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "403": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "404": { "description": "Vault item not found", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false, "description": "Vault item not found" } } } } } } }, "/v1/vault/access/{id}": { "get": { "summary": "Get Vault Access Status", "tags": [ "Vault" ], "description": "Poll the status of a vault access request. Returns status \"pending\" until the user approves on their mobile device. When status becomes \"approved\", the e2eeCiphertext field contains the base64-encoded encrypted payload.", "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "in": "path", "name": "id", "required": true } ], "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "description": "One of: pending, approved, denied, expired, consumed" }, "e2eeCiphertext": { "type": "string", "nullable": true, "description": "Base64-encoded encrypted payload. Present (non-null) only on the first poll after approval, when status transitions to \"consumed\". Null otherwise." }, "expiresAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "status", "e2eeCiphertext", "expiresAt" ], "additionalProperties": false } } } }, "401": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "403": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "404": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } } } } }, "/v1/checkout/initiate": { "post": { "summary": "Initiate Checkout", "tags": [ "Checkout" ], "description": "Agent initiates a checkout (purchase). Sends a push notification to the user for biometric approval of the payment amount + merchant. When invoked with a CIBA-approved token (approve:payment scope), the payment is auto-approved without a second push.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "merchantName": { "type": "string", "minLength": 1, "maxLength": 256 }, "merchantDomain": { "type": "string", "minLength": 1, "maxLength": 512 }, "checkoutUrl": { "type": "string", "format": "uri", "maxLength": 2048 }, "amount": { "type": "integer", "minimum": 1 }, "currency": { "type": "string", "minLength": 3, "maxLength": 3, "default": "USD" }, "lineItems": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string", "minLength": 1, "maxLength": 256 }, "quantity": { "type": "integer", "minimum": 1 }, "price": { "type": "integer", "minimum": 0 } }, "required": [ "title", "quantity", "price" ], "additionalProperties": false }, "minItems": 1, "maxItems": 50 }, "expiresInSecs": { "type": "integer", "minimum": 60, "maximum": 3600, "default": 600 } }, "required": [ "merchantName", "merchantDomain", "checkoutUrl", "amount", "lineItems" ], "additionalProperties": false } } } }, "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "checkoutRequest": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "description": "Initial status — \"pending\" for standard flow, \"approved\" when created with a CIBA auto-approve token, \"completed\" when the auto-approve Stripe payment succeeded synchronously" }, "challengeHex": { "type": "string" }, "expiresAt": { "type": "string", "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" }, "sptId": { "type": "string", "nullable": true, "description": "Stripe Payment Token ID. Present when CIBA auto-approve + Stripe payment succeeded synchronously." }, "paymentIntentId": { "type": "string", "nullable": true, "description": "Stripe PaymentIntent ID. Present when CIBA auto-approve + Stripe payment succeeded synchronously." } }, "required": [ "id", "status", "challengeHex", "expiresAt", "createdAt" ], "additionalProperties": false } }, "required": [ "success", "checkoutRequest" ], "additionalProperties": false } } } }, "400": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "401": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "403": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } } } } }, "/v1/checkout/{id}/status": { "get": { "summary": "Get Checkout Status", "tags": [ "Checkout" ], "description": "Poll checkout status. Returns status \"pending\" until the user approves on mobile. When status becomes \"approved\" and later \"completed\", the orderConfirmation fields will be populated.", "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "in": "path", "name": "id", "required": true } ], "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "checkoutRequest": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "description": "One of: pending, approved, payment_processing, payment_completed, payment_failed, completed, rejected, expired" }, "orderConfirmation": { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "stripe_connect", "stripe_spt" ] }, "sptId": { "type": "string" }, "paymentIntentId": { "type": "string" }, "stripePaymentMethodId": { "type": "string" }, "amount": { "type": "integer" }, "currency": { "type": "string" }, "status": { "type": "string" }, "sptExpiresAt": { "type": "string" }, "error": { "type": "string" }, "chargeId": { "type": "string" }, "paidAt": { "type": "string" }, "failureMessage": { "type": "string" }, "failureCode": { "type": "string" }, "failedAt": { "type": "string" }, "orderId": { "type": "string" }, "metadata": { "type": "object", "additionalProperties": {} } }, "additionalProperties": false, "nullable": true }, "approvedAt": { "type": "string", "format": "date-time", "nullable": true }, "completedAt": { "type": "string", "format": "date-time", "nullable": true }, "expiresAt": { "type": "string", "format": "date-time" }, "sptId": { "type": "string", "nullable": true, "description": "Stripe Payment Token ID. Extracted from orderConfirmation.sptId once the Stripe-based completion path has run. Null on pending / expired / non-Stripe checkouts." }, "paymentIntentId": { "type": "string", "nullable": true, "description": "Stripe PaymentIntent ID. Read from the checkout row's stripe_payment_intent_id column once a PaymentIntent has been created on the merchant's connected account. Null on pending / SPT-only / non-Stripe checkouts." } }, "required": [ "id", "status", "orderConfirmation", "approvedAt", "completedAt", "expiresAt" ], "additionalProperties": false } }, "required": [ "success", "checkoutRequest" ], "additionalProperties": false } } } }, "401": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "403": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "404": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } } } } }, "/v1/merchants/connect": { "get": { "summary": "Merchant Connect", "tags": [ "Payments" ], "description": "Initiate merchant onboarding. Called by e-commerce platform plugins (WooCommerce, Medusa, etc.) to start the connect flow. Creates a session in Redis and redirects the merchant to the BKey approval page where they prove their identity with biometric approval. No authentication required — this endpoint is part of the onboarding handshake.", "parameters": [ { "schema": { "type": "string", "format": "uri" }, "in": "query", "name": "store_url", "required": true }, { "schema": { "type": "string", "enum": [ "woocommerce", "shopify", "medusa", "bigcommerce" ], "default": "woocommerce" }, "in": "query", "name": "platform", "required": false }, { "schema": { "type": "string" }, "in": "query", "name": "return_url", "required": false } ], "responses": { "302": { "description": "Redirect to the BKey approval page. The client must follow the Location header to complete the merchant onboarding handshake.", "headers": { "Location": { "description": "URL to redirect the client to.", "schema": { "type": "string", "format": "uri" } } } }, "400": { "description": "Invalid store_url, unsupported platform, or SSRF rejection", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false, "description": "Invalid store_url, unsupported platform, or SSRF rejection" } } } } }, "security": [] } }, "/v1/payment-sessions/": { "post": { "summary": "Create Payment Session", "tags": [ "Payments" ], "description": "Create a payment session (merchant-facing). Called by plugins (WooCommerce, Medusa, etc.) to start a BKey-approved payment flow. The merchant authenticates with a mk_live_* / mk_test_* API key. Returns an approvalUrl to redirect the shopper to.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "merchantDomain": { "type": "string", "minLength": 1 }, "externalOrderId": { "type": "string" }, "amount": { "type": "integer", "minimum": 1, "maximum": 5000000 }, "currency": { "type": "string", "minLength": 3, "maxLength": 3, "default": "USD" }, "lineItems": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string", "minLength": 1 }, "quantity": { "type": "integer", "minimum": 1 }, "price": { "type": "integer", "minimum": 0 } }, "required": [ "title", "quantity", "price" ], "additionalProperties": false }, "minItems": 1 }, "returnUrl": { "type": "string", "format": "uri" }, "notifyUrl": { "type": "string", "format": "uri" }, "cancelUrl": { "type": "string", "format": "uri" }, "customerEmail": { "type": "string", "format": "email" }, "expiresInSecs": { "type": "integer", "minimum": 60, "maximum": 7200, "default": 1800 } }, "required": [ "amount", "lineItems", "returnUrl" ], "additionalProperties": false } } } }, "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "paymentSession": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "description": "One of: pending, awaiting_approval, approved, completed, rejected, failed, expired, refunded" }, "approvalUrl": { "type": "string", "description": "URL the shopper visits to approve payment" }, "amount": { "type": "integer", "minimum": 0 }, "currency": { "type": "string", "minLength": 3, "maxLength": 3 }, "merchantName": { "type": "string" }, "lineItems": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "quantity": { "type": "integer", "exclusiveMinimum": true, "minimum": 0 }, "price": { "type": "integer", "minimum": 0, "description": "Price in smallest currency unit (e.g., cents)" } }, "required": [ "title", "quantity", "price" ], "additionalProperties": false } }, "expiresAt": { "type": "string", "format": "date-time" }, "merchantDomain": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "externalOrderId": { "type": "string", "nullable": true, "description": "Merchant's own order ID — echoed back so the merchant plugin can correlate the BKey session with the shop's order." }, "sptId": { "type": "string", "nullable": true, "description": "Stripe Payment Token ID. Populated after payment succeeds." }, "paymentIntentId": { "type": "string", "nullable": true, "description": "Stripe PaymentIntent ID. Populated after payment succeeds." }, "returnUrl": { "type": "string", "description": "Merchant success redirect URL." }, "cancelUrl": { "type": "string", "description": "Merchant cancel redirect URL." }, "paymentResult": { "type": "object", "additionalProperties": {}, "description": "Raw payment processor result (Stripe-shaped). Present on completed / failed sessions." } }, "required": [ "id", "status", "approvalUrl", "amount", "currency", "expiresAt" ], "additionalProperties": false } }, "required": [ "success", "paymentSession" ], "additionalProperties": false } } } }, "400": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "401": { "description": "Missing or invalid merchant API key", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false, "description": "Missing or invalid merchant API key" } } } }, "403": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } } }, "security": [ { "merchantApiKey": [] } ] } }, "/v1/payment-sessions/agent": { "post": { "summary": "Create Agent Payment Session", "tags": [ "Payments" ], "description": "Create a payment session (agent-facing). Used when an AI agent initiates a purchase on behalf of the user. When called with a CIBA-approved token (approve:payment scope), the session is auto-approved.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "merchantDomain": { "type": "string", "minLength": 1 }, "externalOrderId": { "type": "string" }, "amount": { "type": "integer", "minimum": 1, "maximum": 5000000 }, "currency": { "type": "string", "minLength": 3, "maxLength": 3, "default": "USD" }, "lineItems": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string", "minLength": 1 }, "quantity": { "type": "integer", "minimum": 1 }, "price": { "type": "integer", "minimum": 0 } }, "required": [ "title", "quantity", "price" ], "additionalProperties": false }, "minItems": 1 }, "returnUrl": { "type": "string", "format": "uri" }, "notifyUrl": { "type": "string", "format": "uri" }, "cancelUrl": { "type": "string", "format": "uri" }, "customerEmail": { "type": "string", "format": "email" }, "expiresInSecs": { "type": "integer", "minimum": 60, "maximum": 7200, "default": 1800 } }, "required": [ "merchantDomain", "amount", "lineItems", "returnUrl" ], "additionalProperties": false } } } }, "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "paymentSession": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "description": "One of: pending, awaiting_approval, approved, completed, rejected, failed, expired, refunded" }, "approvalUrl": { "type": "string", "description": "URL the shopper visits to approve payment" }, "amount": { "type": "integer", "minimum": 0 }, "currency": { "type": "string", "minLength": 3, "maxLength": 3 }, "merchantName": { "type": "string" }, "lineItems": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "quantity": { "type": "integer", "exclusiveMinimum": true, "minimum": 0 }, "price": { "type": "integer", "minimum": 0, "description": "Price in smallest currency unit (e.g., cents)" } }, "required": [ "title", "quantity", "price" ], "additionalProperties": false } }, "expiresAt": { "type": "string", "format": "date-time" }, "merchantDomain": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "externalOrderId": { "type": "string", "nullable": true, "description": "Merchant's own order ID — echoed back so the merchant plugin can correlate the BKey session with the shop's order." }, "sptId": { "type": "string", "nullable": true, "description": "Stripe Payment Token ID. Populated after payment succeeds." }, "paymentIntentId": { "type": "string", "nullable": true, "description": "Stripe PaymentIntent ID. Populated after payment succeeds." }, "returnUrl": { "type": "string", "description": "Merchant success redirect URL." }, "cancelUrl": { "type": "string", "description": "Merchant cancel redirect URL." }, "paymentResult": { "type": "object", "additionalProperties": {}, "description": "Raw payment processor result (Stripe-shaped). Present on completed / failed sessions." } }, "required": [ "id", "status", "approvalUrl", "amount", "currency", "expiresAt" ], "additionalProperties": false } }, "required": [ "success", "paymentSession" ], "additionalProperties": false } } } }, "400": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "401": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "403": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } } } } }, "/v1/payment-sessions/{id}": { "get": { "summary": "Get Payment Session Status", "tags": [ "Payments" ], "description": "Get a payment session (public polling endpoint). Returns non-sensitive fields only — used by the shopper approval page to display payment details and poll for status changes.", "parameters": [ { "schema": { "type": "string", "format": "uuid" }, "in": "path", "name": "id", "required": true } ], "responses": { "200": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean" }, "paymentSession": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "description": "One of: pending, awaiting_approval, approved, completed, rejected, failed, expired, refunded" }, "approvalUrl": { "type": "string", "description": "URL the shopper visits to approve payment" }, "amount": { "type": "integer", "minimum": 0 }, "currency": { "type": "string", "minLength": 3, "maxLength": 3 }, "merchantName": { "type": "string" }, "lineItems": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "quantity": { "type": "integer", "exclusiveMinimum": true, "minimum": 0 }, "price": { "type": "integer", "minimum": 0, "description": "Price in smallest currency unit (e.g., cents)" } }, "required": [ "title", "quantity", "price" ], "additionalProperties": false } }, "expiresAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "status", "approvalUrl", "amount", "currency", "expiresAt" ], "additionalProperties": false } }, "required": [ "success", "paymentSession" ], "additionalProperties": false } } } }, "400": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } }, "404": { "description": "Default Response", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ false ] }, "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code" }, "message": { "type": "string", "description": "Human-readable error message" } }, "required": [ "code", "message" ], "additionalProperties": false } }, "required": [ "success", "error" ], "additionalProperties": false } } } } }, "security": [] } } }, "security": [ { "bearerAuth": [] } ], "tags": [ { "name": "OAuth", "description": "OAuth 2.1 token, device auth, CIBA, revocation" }, { "name": "Checkout", "description": "Agent-initiated checkout with biometric approval" }, { "name": "Vault", "description": "Encrypted secret storage with biometric access" }, { "name": "Payments", "description": "Payment methods and shared payment tokens" }, { "name": "Identity", "description": "DID and identity management" } ], "servers": [ { "url": "https://api.bkey.id", "description": "Production" } ] }