{"owner":"zama-ai","repo":"fhevm","hasSpec":true,"specFile":"relayer/openapi.yml","branch":"HEAD","format":"yaml","version":"3.x (YAML)","title":"fhevm","description":"","endpoints":[],"spec":"openapi: 3.1.0\ninfo:\n  title: Relayer API\n  description: |2\n\n    # Relayer API\n\n    Relayer provides an interface to request input proofs and decryptions for ciphertexts on the Zama\n    Gateway Chain.\n\n    ## Overview\n\n    ### Reading FHE Public Key URLs\n\n    | Endpoint  | Method | Description                      |\n    |-----------|--------|----------------------------------|\n    | Key URL   | `GET`  | Returns FHE public key URLs immediately |\n\n    ### Ciphertext Operations (POST/GET polling)\n\n    | Endpoint                 | POST to submit | GET to poll              |\n    |--------------------------|----------------|--------------------------|\n    | Input Proof              | `/v2/input-proof` | `/v2/input-proof/{jobId}` |\n    | User Decrypt             | `/v2/user-decrypt` | `/v2/user-decrypt/{jobId}` |\n    | Delegated User Decrypt   | `/v2/delegated-user-decrypt` | `/v2/delegated-user-decrypt/{jobId}` |\n    | Public Decrypt           | `/v2/public-decrypt` | `/v2/public-decrypt/{jobId}` |\n\n    **Polling flow:**\n\n    1. `POST /v2/{endpoint}` — returns `202` with a `jobId`.\n    2. `GET /v2/{endpoint}/{jobId}` — returns `202` + `Retry-After` while processing.\n    3. Final `GET` — returns `200` with the result, or `4xx`/`5xx` with an `error.label`.\n\n    ## Authentication\n\n    Pass the `X-API-Key` header with every request. Optional on testnet, required on mainnet.\n\n    ## Response Format\n\n    All responses share a common envelope:\n\n    ```json\n    {\n      \"status\": \"queued\" | \"succeeded\" | \"failed\",\n      \"requestId\": \"uuid\",\n      \"result\": { ... },\n      \"error\": { \"label\": \"...\", \"message\": \"...\", \"details\": [...] }\n    }\n    ```\n\n    | Field     | Present when                                          |\n    |-----------|-------------------------------------------------------|\n    | `status`  | Always                                                |\n    | `result`  | Success (`200`)                                       |\n    | `error`   | Failure — match on `error.label` (see Error Handling) |\n    | `details` | Validation errors (`400`) with per-field issues       |\n\n    The `Retry-After` header appears in two contexts:\n\n    | Context    | Status | Meaning                              |\n    |------------|--------|--------------------------------------|\n    | Polling    | 202    | Suggested interval before next GET   |\n    | Rate limit | 429    | Minimum wait before retrying POST    |\n\n    Always respect this header to avoid unnecessary requests.\n\n    ## Error Handling\n\n    All error responses include a machine-readable `label` field. Each error response also has one or more named examples you can expand below.\n\n    ### Fix and retry (client errors)\n\n    | Label | HTTP | What to fix |\n    |-------|------|-------------|\n    | `malformed_json` | 400 | Fix JSON syntax |\n    | `missing_fields` | 400 | Add required fields (see `details[]`) |\n    | `validation_failed` | 400 | Fix field values (see `details[]`) |\n    | `request_error` | 400 | Fix request body |\n    | `host_chain_id_not_supported` | 400 | Use supported chain ID |\n    | `not_allowed_on_host_acl` | 400 | Contact operator to allowlist contract |\n    | `not_found` | 404 | Check job ID validity |\n\n    ### Retry with backoff (transient errors)\n\n    | Label | HTTP | Guidance |\n    |-------|------|----------|\n    | `rate_limited` | 429 | Wait `Retry-After` seconds |\n    | `host_acl_failed` | 500 | Retry; if persistent, contact operator |\n    | `readiness_check_timed_out` | 503 | Retry with backoff |\n    | `response_timed_out` | 503 | Retry with backoff |\n    | `protocol_paused` | 503 | Wait for unpause |\n    | `gateway_not_reachable` | 503 | Retry with backoff |\n\n    ### Contact operator (infrastructure)\n\n    | Label | HTTP | Guidance |\n    |-------|------|----------|\n    | `internal_server_error` | 500 | Contact operator with `requestId` |\n    | `insufficient_balance` | 503 | Contact operator |\n    | `insufficient_allowance` | 503 | Contact operator |\n\n\n    ## Conventions\n\n    | Value                | Format                                |\n    |----------------------|---------------------------------------|\n    | Ethereum addresses   | `0x` + 40 hex chars                   |\n    | Ciphertext handles   | `0x` + 64 hex chars                   |\n    | Extra data           | Always `\"0x00\"`                       |\n    | Signatures (request) | Raw hex, 130 chars, no `0x` prefix    |\n    | Public keys          | Raw hex, min 2 chars, no `0x` prefix  |\n  contact:\n    name: Zama\n    url: https://www.zama.ai\n  license:\n    name: BSD-3-Clause-Clear\n    url: https://opensource.org/licenses/BSD-3-Clause-Clear\n  version: 0.14.0\nservers:\n- url: /\n  description: Current server\n- url: http://localhost:3000\n  description: Local development\npaths:\n  /v2/keyurl:\n    get:\n      tags:\n      - Key URL\n      summary: Retrieve FHE key material URLs.\n      operationId: keyurl_v2\n      responses:\n        '200':\n          description: FHE public key URLs.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/KeyUrlResponseJson'\n        '500':\n          description: 'Internal server error. Error label: `internal_server_error`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                InternalServerError:\n                  summary: Key URL not yet initialized\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Key URL not yet initialized\n                    status: failed\n  /v2/input-proof:\n    post:\n      tags:\n      - Input Proof\n      summary: Submit input proof verification.\n      operationId: input_proof_post_v2\n      requestBody:\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/InputProofRequestJson'\n        required: true\n      responses:\n        '202':\n          description: Request accepted for processing.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/InputProofPostResponseJson'\n        '400':\n          description: 'Invalid request. Error label is one of: `malformed_json`, `missing_fields`, `validation_failed`, `request_error`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                MalformedJson:\n                  summary: Could not parse request body as JSON\n                  value:\n                    error:\n                      label: malformed_json\n                      message: Could not parse request body as JSON\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                MissingFields:\n                  summary: Required fields are missing\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: missing_fields\n                      message: Required fields are missing\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                RequestError:\n                  summary: Invalid request\n                  value:\n                    error:\n                      label: request_error\n                      message: Invalid request\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ValidationFailed:\n                  summary: Request validation failed\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: validation_failed\n                      message: Request validation failed\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '429':\n          description: 'Rate limited. Error label: `rate_limited`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                RateLimited:\n                  summary: Too many requests — retry after the Retry-After interval\n                  value:\n                    error:\n                      label: rate_limited\n                      message: Too many requests — retry after the Retry-After interval\n                    status: failed\n        '500':\n          description: 'Internal server error. Error label: `internal_server_error`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                InternalServerError:\n                  summary: Internal server error\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Internal server error\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n  /v2/input-proof/{job_id}:\n    get:\n      tags:\n      - Input Proof\n      summary: Check input proof status.\n      operationId: input_proof_get_v2\n      parameters:\n      - name: job_id\n        in: path\n        description: Job ID returned from POST request\n        required: true\n        schema:\n          type: string\n          format: uuid\n      responses:\n        '200':\n          description: Completed.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/InputProofSucceededStatusResponse'\n        '202':\n          description: Still processing. Poll again after Retry-After.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusQueued'\n              example:\n                requestId: 550e8400-e29b-41d4-a716-446655440000\n                status: queued\n        '400':\n          description: 'Request failed. Error label: `validation_failed`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                ValidationFailed:\n                  summary: Signature is invalid\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: validation_failed\n                      message: Signature is invalid\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '404':\n          description: 'Not found. Error label: `not_found`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                NotFound:\n                  summary: Request not found\n                  value:\n                    error:\n                      label: not_found\n                      message: Request not found\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '500':\n          description: 'Internal server error. Error label: `internal_server_error`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                InternalServerError:\n                  summary: Internal server error\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Internal server error\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '503':\n          description: 'Service unavailable. Error label is one of: `response_timed_out`, `protocol_paused`, `insufficient_balance`, `insufficient_allowance`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                InsufficientAllowance:\n                  summary: Insufficient allowance for transaction\n                  value:\n                    error:\n                      label: insufficient_allowance\n                      message: Insufficient allowance for transaction\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                InsufficientBalance:\n                  summary: Insufficient balance for transaction\n                  value:\n                    error:\n                      label: insufficient_balance\n                      message: Insufficient balance for transaction\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ProtocolPaused:\n                  summary: Protocol is paused\n                  value:\n                    error:\n                      label: protocol_paused\n                      message: Protocol is paused\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ResponseTimedOut:\n                  summary: Request processing timed out\n                  value:\n                    error:\n                      label: response_timed_out\n                      message: Request processing timed out\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n  /v2/user-decrypt:\n    post:\n      tags:\n      - User Decrypt\n      summary: Submit user decryption.\n      description: |-\n        **Deprecated.** Superseded by `POST /v3/user-decrypt` (unified EIP-712\n        user-decryption). The v2 surface remains available throughout the\n        deprecation window.\n      operationId: user_decrypt_post_v2\n      requestBody:\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/UserDecryptRequestJson'\n        required: true\n      responses:\n        '202':\n          description: Request accepted for processing.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserDecryptPostResponseJson'\n        '400':\n          description: 'Invalid request. Error label is one of: `malformed_json`, `missing_fields`, `validation_failed`, `request_error`, `host_chain_id_not_supported`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                HostChainIdNotSupported:\n                  summary: Chain ID is not supported by this relayer\n                  value:\n                    error:\n                      label: host_chain_id_not_supported\n                      message: Chain ID is not supported by this relayer\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                MalformedJson:\n                  summary: Could not parse request body as JSON\n                  value:\n                    error:\n                      label: malformed_json\n                      message: Could not parse request body as JSON\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                MissingFields:\n                  summary: Required fields are missing\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: missing_fields\n                      message: Required fields are missing\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                RequestError:\n                  summary: Invalid request\n                  value:\n                    error:\n                      label: request_error\n                      message: Invalid request\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ValidationFailed:\n                  summary: Request validation failed\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: validation_failed\n                      message: Request validation failed\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '429':\n          description: 'Rate limited. Error label: `rate_limited`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                RateLimited:\n                  summary: Too many requests — retry after the Retry-After interval\n                  value:\n                    error:\n                      label: rate_limited\n                      message: Too many requests — retry after the Retry-After interval\n                    status: failed\n        '500':\n          description: 'Internal server error. Error label: `internal_server_error`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                InternalServerError:\n                  summary: Internal server error\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Internal server error\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n      deprecated: true\n  /v2/user-decrypt/{job_id}:\n    get:\n      tags:\n      - User Decrypt\n      summary: Check user decryption status.\n      operationId: user_decrypt_get_v2\n      parameters:\n      - name: job_id\n        in: path\n        description: Job ID returned from POST request\n        required: true\n        schema:\n          type: string\n          format: uuid\n      responses:\n        '200':\n          description: Completed.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserDecryptSucceededStatusResponse'\n        '202':\n          description: Still processing. Poll again after Retry-After.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusQueued'\n              example:\n                requestId: 550e8400-e29b-41d4-a716-446655440000\n                status: queued\n        '400':\n          description: 'Request failed. Error label is one of: `validation_failed`, `not_allowed_on_host_acl`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                NotAllowedOnHostAcl:\n                  summary: Contract is not on the host ACL\n                  value:\n                    error:\n                      label: not_allowed_on_host_acl\n                      message: Contract is not on the host ACL\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ValidationFailed:\n                  summary: Signature is invalid\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: validation_failed\n                      message: Signature is invalid\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '404':\n          description: 'Not found. Error label: `not_found`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                NotFound:\n                  summary: Request not found\n                  value:\n                    error:\n                      label: not_found\n                      message: Request not found\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '500':\n          description: 'Internal server error. Error label is one of: `internal_server_error`, `host_acl_failed`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                HostAclFailed:\n                  summary: Failed to check host ACL\n                  value:\n                    error:\n                      label: host_acl_failed\n                      message: Failed to check host ACL\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                InternalServerError:\n                  summary: Internal server error\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Internal server error\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '503':\n          description: 'Service unavailable. Error label is one of: `response_timed_out`, `readiness_check_timed_out`, `protocol_paused`, `insufficient_balance`, `insufficient_allowance`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                InsufficientAllowance:\n                  summary: Insufficient allowance for transaction\n                  value:\n                    error:\n                      label: insufficient_allowance\n                      message: Insufficient allowance for transaction\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                InsufficientBalance:\n                  summary: Insufficient balance for transaction\n                  value:\n                    error:\n                      label: insufficient_balance\n                      message: Insufficient balance for transaction\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ProtocolPaused:\n                  summary: Protocol is paused\n                  value:\n                    error:\n                      label: protocol_paused\n                      message: Protocol is paused\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ReadinessCheckTimedOut:\n                  summary: Readiness check timed out\n                  value:\n                    error:\n                      label: readiness_check_timed_out\n                      message: Readiness check timed out\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ResponseTimedOut:\n                  summary: Request processing timed out\n                  value:\n                    error:\n                      label: response_timed_out\n                      message: Request processing timed out\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n  /v2/delegated-user-decrypt:\n    post:\n      tags:\n      - Delegated User Decrypt\n      summary: Submit delegated user decryption.\n      description: |-\n        **Deprecated.** Superseded by `POST /v3/user-decrypt` (unified EIP-712\n        user-decryption — delegated handles use the per-entry `ownerAddress`).\n        The v2 surface remains available throughout the deprecation window.\n      operationId: delegated_user_decrypt_post_v2\n      requestBody:\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/DelegatedUserDecryptRequestJson'\n        required: true\n      responses:\n        '202':\n          description: Request accepted for processing.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserDecryptPostResponseJson'\n        '400':\n          description: 'Invalid request. Error label is one of: `malformed_json`, `missing_fields`, `validation_failed`, `request_error`, `host_chain_id_not_supported`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                HostChainIdNotSupported:\n                  summary: Chain ID is not supported by this relayer\n                  value:\n                    error:\n                      label: host_chain_id_not_supported\n                      message: Chain ID is not supported by this relayer\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                MalformedJson:\n                  summary: Could not parse request body as JSON\n                  value:\n                    error:\n                      label: malformed_json\n                      message: Could not parse request body as JSON\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                MissingFields:\n                  summary: Required fields are missing\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: missing_fields\n                      message: Required fields are missing\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                RequestError:\n                  summary: Invalid request\n                  value:\n                    error:\n                      label: request_error\n                      message: Invalid request\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ValidationFailed:\n                  summary: Request validation failed\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: validation_failed\n                      message: Request validation failed\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '429':\n          description: 'Rate limited. Error label: `rate_limited`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                RateLimited:\n                  summary: Too many requests — retry after the Retry-After interval\n                  value:\n                    error:\n                      label: rate_limited\n                      message: Too many requests — retry after the Retry-After interval\n                    status: failed\n        '500':\n          description: 'Internal server error. Error label: `internal_server_error`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                InternalServerError:\n                  summary: Internal server error\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Internal server error\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n      deprecated: true\n  /v2/delegated-user-decrypt/{job_id}:\n    get:\n      tags:\n      - Delegated User Decrypt\n      summary: Check delegated user decryption status.\n      operationId: delegated_user_decrypt_get_v2\n      parameters:\n      - name: job_id\n        in: path\n        description: Job ID returned from POST request\n        required: true\n        schema:\n          type: string\n          format: uuid\n      responses:\n        '200':\n          description: Completed.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserDecryptSucceededStatusResponse'\n        '202':\n          description: Still processing. Poll again after Retry-After.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusQueued'\n              example:\n                requestId: 550e8400-e29b-41d4-a716-446655440000\n                status: queued\n        '400':\n          description: 'Request failed. Error label is one of: `validation_failed`, `not_allowed_on_host_acl`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                NotAllowedOnHostAcl:\n                  summary: Contract is not on the host ACL\n                  value:\n                    error:\n                      label: not_allowed_on_host_acl\n                      message: Contract is not on the host ACL\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ValidationFailed:\n                  summary: Signature is invalid\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: validation_failed\n                      message: Signature is invalid\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '404':\n          description: 'Not found. Error label: `not_found`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                NotFound:\n                  summary: Request not found\n                  value:\n                    error:\n                      label: not_found\n                      message: Request not found\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '500':\n          description: 'Internal server error. Error label is one of: `internal_server_error`, `host_acl_failed`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                HostAclFailed:\n                  summary: Failed to check host ACL\n                  value:\n                    error:\n                      label: host_acl_failed\n                      message: Failed to check host ACL\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                InternalServerError:\n                  summary: Internal server error\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Internal server error\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '503':\n          description: 'Service unavailable. Error label is one of: `response_timed_out`, `readiness_check_timed_out`, `protocol_paused`, `insufficient_balance`, `insufficient_allowance`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                InsufficientAllowance:\n                  summary: Insufficient allowance for transaction\n                  value:\n                    error:\n                      label: insufficient_allowance\n                      message: Insufficient allowance for transaction\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                InsufficientBalance:\n                  summary: Insufficient balance for transaction\n                  value:\n                    error:\n                      label: insufficient_balance\n                      message: Insufficient balance for transaction\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ProtocolPaused:\n                  summary: Protocol is paused\n                  value:\n                    error:\n                      label: protocol_paused\n                      message: Protocol is paused\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ReadinessCheckTimedOut:\n                  summary: Readiness check timed out\n                  value:\n                    error:\n                      label: readiness_check_timed_out\n                      message: Readiness check timed out\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ResponseTimedOut:\n                  summary: Request processing timed out\n                  value:\n                    error:\n                      label: response_timed_out\n                      message: Request processing timed out\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n  /v2/public-decrypt:\n    post:\n      tags:\n      - Public Decrypt\n      summary: Submit public decryption.\n      operationId: public_decrypt_post_v2\n      requestBody:\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/PublicDecryptRequestJson'\n        required: true\n      responses:\n        '202':\n          description: Request accepted for processing.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PublicDecryptPostResponseJson'\n        '400':\n          description: 'Invalid request. Error label is one of: `malformed_json`, `missing_fields`, `validation_failed`, `request_error`, `host_chain_id_not_supported`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                HostChainIdNotSupported:\n                  summary: Chain ID is not supported by this relayer\n                  value:\n                    error:\n                      label: host_chain_id_not_supported\n                      message: Chain ID is not supported by this relayer\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                MalformedJson:\n                  summary: Could not parse request body as JSON\n                  value:\n                    error:\n                      label: malformed_json\n                      message: Could not parse request body as JSON\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                MissingFields:\n                  summary: Required fields are missing\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: missing_fields\n                      message: Required fields are missing\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                RequestError:\n                  summary: Invalid request\n                  value:\n                    error:\n                      label: request_error\n                      message: Invalid request\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ValidationFailed:\n                  summary: Request validation failed\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: validation_failed\n                      message: Request validation failed\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '429':\n          description: 'Rate limited. Error label: `rate_limited`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                RateLimited:\n                  summary: Too many requests — retry after the Retry-After interval\n                  value:\n                    error:\n                      label: rate_limited\n                      message: Too many requests — retry after the Retry-After interval\n                    status: failed\n        '500':\n          description: 'Internal server error. Error label: `internal_server_error`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n              examples:\n                InternalServerError:\n                  summary: Internal server error\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Internal server error\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n  /v2/public-decrypt/{job_id}:\n    get:\n      tags:\n      - Public Decrypt\n      summary: Check public decryption status.\n      operationId: public_decrypt_get_v2\n      parameters:\n      - name: job_id\n        in: path\n        description: Job ID returned from POST request\n        required: true\n        schema:\n          type: string\n          format: uuid\n      responses:\n        '200':\n          description: Completed.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/PublicDecryptSucceededStatusResponse'\n        '202':\n          description: Still processing. Poll again after Retry-After.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusQueued'\n              example:\n                requestId: 550e8400-e29b-41d4-a716-446655440000\n                status: queued\n        '400':\n          description: 'Request failed. Error label is one of: `validation_failed`, `not_allowed_on_host_acl`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                NotAllowedOnHostAcl:\n                  summary: Contract is not on the host ACL\n                  value:\n                    error:\n                      label: not_allowed_on_host_acl\n                      message: Contract is not on the host ACL\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ValidationFailed:\n                  summary: Signature is invalid\n                  value:\n                    error:\n                      details:\n                      - field: fieldName\n                        issue: Validation issue description\n                      label: validation_failed\n                      message: Signature is invalid\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '404':\n          description: 'Not found. Error label: `not_found`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                NotFound:\n                  summary: Request not found\n                  value:\n                    error:\n                      label: not_found\n                      message: Request not found\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '500':\n          description: 'Internal server error. Error label is one of: `internal_server_error`, `host_acl_failed`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                HostAclFailed:\n                  summary: Failed to check host ACL\n                  value:\n                    error:\n                      label: host_acl_failed\n                      message: Failed to check host ACL\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                InternalServerError:\n                  summary: Internal server error\n                  value:\n                    error:\n                      label: internal_server_error\n                      message: Internal server error\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n        '503':\n          description: 'Service unavailable. Error label is one of: `response_timed_out`, `readiness_check_timed_out`, `protocol_paused`, `insufficient_balance`, `insufficient_allowance`'\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n              examples:\n                InsufficientAllowance:\n                  summary: Insufficient allowance for transaction\n                  value:\n                    error:\n                      label: insufficient_allowance\n                      message: Insufficient allowance for transaction\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                InsufficientBalance:\n                  summary: Insufficient balance for transaction\n                  value:\n                    error:\n                      label: insufficient_balance\n                      message: Insufficient balance for transaction\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ProtocolPaused:\n                  summary: Protocol is paused\n                  value:\n                    error:\n                      label: protocol_paused\n                      message: Protocol is paused\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ReadinessCheckTimedOut:\n                  summary: Readiness check timed out\n                  value:\n                    error:\n                      label: readiness_check_timed_out\n                      message: Readiness check timed out\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n                ResponseTimedOut:\n                  summary: Request processing timed out\n                  value:\n                    error:\n                      label: response_timed_out\n                      message: Request processing timed out\n                    requestId: 550e8400-e29b-41d4-a716-446655440000\n                    status: failed\n  /v3/user-decrypt:\n    post:\n      tags:\n      - User Decrypt v3\n      summary: Submit a v3 (unified EIP-712) user-decryption request.\n      operationId: user_decrypt_post_v3\n      requestBody:\n        content:\n          application/json:\n            schema:\n              $ref: '#/components/schemas/AttestedUserDecryptRequestJson'\n        required: true\n      responses:\n        '202':\n          description: Request accepted for processing.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserDecryptPostResponseJson'\n        '400':\n          description: Invalid request\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n        '429':\n          description: Rate limited\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n        '500':\n          description: Internal server error\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/RelayerV2ResponseFailed'\n  /v3/user-decrypt/{job_id}:\n    get:\n      tags:\n      - User Decrypt v3\n      summary: Check v3 user-decryption status.\n      operationId: user_decrypt_get_v3\n      parameters:\n      - name: job_id\n        in: path\n        description: Job ID returned from POST request\n        required: true\n        schema:\n          type: string\n          format: uuid\n      responses:\n        '200':\n          description: Completed.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/UserDecryptSucceededStatusResponse'\n        '202':\n          description: Still processing. Poll again after Retry-After.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusQueued'\n              example:\n                requestId: 550e8400-e29b-41d4-a716-446655440000\n                status: queued\n        '400':\n          description: Request failed\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n        '404':\n          description: Not found\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n        '500':\n          description: Internal server error\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n        '503':\n          description: Service unavailable\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/V2StatusFailed'\n  /liveness:\n    get:\n      tags:\n      - Health\n      summary: Liveness probe\n      operationId: liveness_handler\n      responses:\n        '200':\n          description: Service is alive.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/LivenessResponse'\n      security:\n      - {}\n  /healthz:\n    get:\n      tags:\n      - Health\n      summary: Health check with dependency status\n      operationId: health_handler\n      responses:\n        '200':\n          description: Service is healthy.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/HealthResponse'\n        '503':\n          description: Service is unhealthy.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/HealthResponse'\n      security:\n      - {}\n  /version:\n    get:\n      tags:\n      - Health\n      summary: Build version and git info\n      operationId: version_handler\n      responses:\n        '200':\n          description: Version information.\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/VersionResponse'\n      security:\n      - {}\ncomponents:\n  schemas:\n    AttestedUserDecryptRequestJson:\n      type: object\n      description: |-\n        v3 user-decrypt request envelope. The relayer dispatches strictly by\n        `attestationType`; the currently supported value is\n        `\"eip712-unified-user-decrypt-v1\"`. Adding a Solana attestation later is\n        a one-line widening of the dispatch table, not a v4 bump.\n      required:\n      - attestationType\n      - attestedPayload\n      - signature\n      properties:\n        attestationType:\n          type: string\n          description: |-\n            The attestation/signature scheme used for the `signature` bytes.\n            Must equal `\"eip712-unified-user-decrypt-v1\"` for the current\n            release.\n          example: eip712-unified-user-decrypt-v1\n        attestedPayload:\n          $ref: '#/components/schemas/Eip712UnifiedUserDecryptPayloadJson'\n          description: |-\n            The EIP-712 Unified User-Decryption Request payload that the\n            `signature` attests over.\n        signature:\n          type: string\n          description: |-\n            Attestation signature: `0x`-hex, or empty for the ERC-1271\n            empty-signature path.\n          example: '0xaabbccddeeff'\n      additionalProperties: false\n    ChainId:\n      oneOf:\n      - type: string\n        examples:\n        - '0xaa36a7'\n        - '11155111'\n      - type: integer\n        format: int64\n        example: 11155111\n        minimum: 0\n      description: |-\n        Chain Id\n\n        It does support an ID as an integer or a 0x prefixed hex string\n    DelegatedUserDecryptRequestJson:\n      type: object\n      required:\n      - handleContractPairs\n      - contractsChainId\n      - contractAddresses\n      - delegatorAddress\n      - delegateAddress\n      - startTimestamp\n      - durationDays\n      - signature\n      - publicKey\n      - extraData\n      properties:\n        contractAddresses:\n          type: array\n          items:\n            type: string\n          example:\n          - \"0x1234567890123456789012345678901234567890\"\n          minItems: 1\n        contractsChainId:\n          $ref: '#/components/schemas/ChainId'\n        delegateAddress:\n          type: string\n          description: Ethereum address of the delegate (the party authorized to decrypt). `0x` + 40 hex chars.\n          example: \"0x1234567890123456789012345678901234567890\"\n        delegatorAddress:\n          type: string\n          description: Ethereum address of the delegator (the user who owns the ciphertexts). `0x` + 40 hex chars.\n          example: \"0x1234567890123456789012345678901234567890\"\n        durationDays:\n          type: string\n          description: Duration of the delegation in days. Decimal string.\n          example: '1'\n        extraData:\n          type: string\n          description: Extra data forwarded verbatim to the gateway contract. Accepts `\"0x00\"`, version `0x01` (`0x01` + 32-byte contextId), or version `0x02` (`0x02` + 32-byte contextId + 32-byte epochId). contextId must be 0x07-tagged and epochId must be 0x08-tagged (first byte of each).\n          example: '0x00'\n        handleContractPairs:\n          type: array\n          items:\n            $ref: '#/components/schemas/HandleContractPairJson'\n        publicKey:\n          type: string\n          description: Delegate's public key for re-encryption. Raw hex, no `0x` prefix, minimum 2 chars.\n          example: \"04b8e5d3f1a2c4e6d8f0a1b3c5d7e9f1a2b4c6d8e0f2a3b5c7d9e1f3a5b7c9d1\"\n        signature:\n          type: string\n          description: EIP-712 signature over the delegation request, signed by the delegator. Raw hex, 130 chars, no `0x` prefix.\n          example: \"aabbccdd00112233445566778899aabbccdd00112233445566778899aabbccdd00112233445566778899aabbccdd00112233445566778899aabbccdd0011223344\"\n        startTimestamp:\n          type: string\n          description: Unix timestamp (seconds) when the delegation starts. Decimal string.\n          example: '1700000000'\n    Eip712UnifiedUserDecryptPayloadJson:\n      type: object\n      description: |-\n        The EIP-712 Unified User-Decryption Request payload (the\n        `attestedPayload` body of the envelope).\n      required:\n      - version\n      - type\n      - handles\n      - userAddress\n      - allowedContracts\n      - requestValidity\n      - publicKey\n      - extraData\n      properties:\n        allowedContracts:\n          type: array\n          items:\n            type: string\n          description: |-\n            Allowlist of contracts whose handles may be decrypted under this\n            request. May be empty (permissive mode).\n          example:\n          - \"0x1234567890123456789012345678901234567890\"\n        extraData:\n          type: string\n          description: Extra data forwarded verbatim to the gateway contract. Accepts `\"0x00\"`, version `0x01` (`0x01` + 32-byte contextId), or version `0x02` (`0x02` + 32-byte contextId + 32-byte epochId). contextId must be 0x07-tagged and epochId must be 0x08-tagged (first byte of each).\n          example: '0x00'\n        handles:\n          type: array\n          items:\n            $ref: '#/components/schemas/HandleEntryJson'\n          description: |-\n            One entry per ciphertext handle to decrypt. The list must be\n            non-empty and must not exceed the existing v2 handle-count bound\n            applied via `validate_handle_entries`.\n        publicKey:\n          type: string\n          description: |-\n            User's public key for re-encryption. `0x` + hex, minimum 2 hex\n            chars after the prefix.\n          example: \"0x04b8e5d3f1a2c4e6d8f0a1b3c5d7e9f1a2b4c6d8e0f2a3b5c7d9e1f3a5b7c9d1\"\n        requestValidity:\n          $ref: '#/components/schemas/RequestValiditySecondsJson'\n          description: Validity window for the request, in seconds.\n        type:\n          type: string\n          description: Must equal `\"user_decryption\"`.\n          example: user_decryption\n        userAddress:\n          type: string\n          description: On-chain caller for the unified gateway call. `0x` + 40 hex chars.\n          example: \"0x1234567890123456789012345678901234567890\"\n        version:\n          type: string\n          description: Must equal `\"2.0\"`.\n          example: '2.0'\n      additionalProperties: false\n    FheKeyInfo:\n      type: object\n      required:\n      - fhePublicKey\n      properties:\n        fhePublicKey:\n          $ref: '#/components/schemas/KeyData'\n    HandleContractPairJson:\n      type: object\n      required:\n      - handle\n      - contractAddress\n      properties:\n        contractAddress:\n          type: string\n          description: Address of the contract that produced this ciphertext handle. `0x` + 40 hex chars.\n          example: \"0x1234567890123456789012345678901234567890\"\n        handle:\n          type: string\n          description: Ciphertext handle from an on-chain FHE operation. `0x` + 64 hex chars.\n          example: \"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890\"\n    HandleEntryJson:\n      type: object\n      description: |-\n        A single handle entry in the unified EIP-712 user-decryption payload.\n        Carries the `ownerAddress` for that handle alongside the handle and its\n        originating contract address.\n      required:\n      - ctHandle\n      - contractAddress\n      - ownerAddress\n      properties:\n        contractAddress:\n          type: string\n          description: Address of the contract that produced this ciphertext handle. `0x` + 40 hex chars.\n          example: \"0x1234567890123456789012345678901234567890\"\n        ctHandle:\n          type: string\n          description: Ciphertext handle from an on-chain FHE operation. `0x` + 64 hex chars.\n          example: \"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890\"\n        ownerAddress:\n          type: string\n          description: |-\n            Owner address for this handle. For direct-access handles this equals\n            the request's `userAddress`; for delegated handles it differs.\n            `0x` + 40 hex chars.\n          example: \"0x1234567890123456789012345678901234567890\"\n    HealthResponse:\n      type: object\n      required:\n      - status\n      properties:\n        dependencies:\n          type:\n          - object\n          - 'null'\n          additionalProperties:\n            type: string\n          propertyNames:\n            type: string\n        status:\n          type: string\n          example: healthy\n    InputProofPostResponseJson:\n      type: object\n      required:\n      - status\n      - requestId\n      - result\n      properties:\n        requestId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n        result:\n          $ref: '#/components/schemas/InputProofQueuedResult'\n        status:\n          type: string\n          example: queued\n    InputProofQueuedResult:\n      type: object\n      required:\n      - jobId\n      properties:\n        jobId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n    InputProofRequestJson:\n      type: object\n      required:\n      - contractChainId\n      - contractAddress\n      - userAddress\n      - ciphertextWithInputVerification\n      - extraData\n      properties:\n        ciphertextWithInputVerification:\n          type: string\n          description: ABI-encoded ciphertext with its ZKPoK input verification data. Raw hex, no `0x` prefix.\n          example: \"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0\"\n        contractAddress:\n          type: string\n          example: \"0x1234567890123456789012345678901234567890\"\n        contractChainId:\n          $ref: '#/components/schemas/ChainId'\n        extraData:\n          type: string\n          description: Extra data forwarded to the gateway contract. Always `\"0x00\"` in the current protocol version.\n          example: '0x00'\n        userAddress:\n          type: string\n          example: \"0x1234567890123456789012345678901234567890\"\n    InputProofResponseJson:\n      type: object\n      required:\n      - accepted\n      - extraData\n      properties:\n        accepted:\n          type: boolean\n          description: Whether the input proof verification was accepted by the gateway.\n          example: true\n        extraData:\n          type: string\n          description: Extra data echoed back from the gateway contract. `0x`-prefixed hex.\n          example: '0x00'\n        handles:\n          type:\n          - array\n          - 'null'\n          items:\n            type: string\n          description: Verified ciphertext handles. Present only when `accepted` is `true`. Each handle is `0x` + 64 hex chars.\n          example:\n          - \"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890\"\n        signatures:\n          type:\n          - array\n          - 'null'\n          items:\n            type: string\n          description: Gateway signatures over the verified handles. Present only when `accepted` is `true`. Each is `0x`-prefixed hex.\n          example:\n          - \"0x1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d\"\n    InputProofSucceededStatusResponse:\n      type: object\n      description: GET 200 — input proof verification succeeded (has result, no error).\n      required:\n      - status\n      - requestId\n      - result\n      properties:\n        requestId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n        result:\n          $ref: '#/components/schemas/InputProofResponseJson'\n        status:\n          type: string\n          example: succeeded\n    KeyData:\n      type: object\n      required:\n      - dataId\n      - urls\n      properties:\n        dataId:\n          type: string\n          description: On-chain key/CRS identifier, as a `0x`-prefixed 32-byte big-endian hex string.\n          example: \"0x0400000000000000000000000000000000000000000000000000000000000003\"\n        urls:\n          type: array\n          items:\n            type: string\n          description: Storage URLs for the key/CRS material.\n    KeyUrlResponseJson:\n      type: object\n      required:\n      - status\n      - response\n      properties:\n        response:\n          $ref: '#/components/schemas/Response'\n        status:\n          type: string\n          example: succeeded\n    LivenessResponse:\n      type: object\n      required:\n      - status\n      properties:\n        status:\n          type: string\n          example: alive\n    PublicDecryptPostResponseJson:\n      type: object\n      required:\n      - status\n      - requestId\n      - result\n      properties:\n        requestId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n        result:\n          $ref: '#/components/schemas/PublicDecryptQueuedResult'\n        status:\n          type: string\n          example: queued\n    PublicDecryptQueuedResult:\n      type: object\n      required:\n      - jobId\n      properties:\n        jobId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n    PublicDecryptRequestJson:\n      type: object\n      required:\n      - ciphertextHandles\n      - extraData\n      properties:\n        ciphertextHandles:\n          type: array\n          items:\n            type: string\n          description: Ciphertext handles to decrypt. Each is `0x` + 64 hex chars, obtained from an on-chain FHE operation.\n          example:\n          - \"0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890\"\n          minItems: 1\n        extraData:\n          type: string\n          description: Extra data forwarded verbatim to the gateway contract. Accepts `\"0x00\"`, version `0x01` (`0x01` + 32-byte contextId), or version `0x02` (`0x02` + 32-byte contextId + 32-byte epochId). contextId must be 0x07-tagged and epochId must be 0x08-tagged (first byte of each).\n          example: '0x00'\n    PublicDecryptResponseJson:\n      type: object\n      required:\n      - decryptedValue\n      - signatures\n      - extraData\n      properties:\n        decryptedValue:\n          type: string\n          description: Decrypted plaintext value. Raw hex, no `0x` prefix.\n          example: '00000000000000000000000000000001'\n        extraData:\n          type: string\n          description: Extra data echoed back from the gateway contract. `0x`-prefixed hex.\n          example: '0x00'\n        signatures:\n          type: array\n          items:\n            type: string\n          description: Gateway signatures over the decrypted value. Raw hex, no `0x` prefix.\n          example:\n          - \"1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d\"\n    PublicDecryptSucceededStatusResponse:\n      type: object\n      description: GET 200 — public decryption succeeded (has result, no error).\n      required:\n      - status\n      - requestId\n      - result\n      properties:\n        requestId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n        result:\n          $ref: '#/components/schemas/PublicDecryptResponseJson'\n        status:\n          type: string\n          example: succeeded\n    RelayerV2ErrorDetail:\n      type: object\n      required:\n      - field\n      - issue\n      properties:\n        field:\n          type: string\n          example: contractAddress\n        issue:\n          type: string\n          example: Must be a valid 42-character hex address with 0x prefix\n    RelayerV2ResponseFailed:\n      type: object\n      description: Failed response wrapper (POST error responses).\n      required:\n      - status\n      - error\n      properties:\n        error:\n          $ref: '#/components/schemas/V2ErrorResponseBody'\n        requestId:\n          type:\n          - string\n          - 'null'\n          example: 550e8400-e29b-41d4-a716-446655440000\n        status:\n          type: string\n          example: failed\n    RequestValidityJson:\n      type: object\n      required:\n      - startTimestamp\n      - durationDays\n      properties:\n        durationDays:\n          type: string\n          description: Number of days the request remains valid. Decimal string.\n          example: '1'\n        startTimestamp:\n          type: string\n          description: Unix timestamp (seconds) when this request becomes valid. Decimal string.\n          example: '1700000000'\n    RequestValiditySecondsJson:\n      type: object\n      description: |-\n        Request-validity window for the unified EIP-712 payload. Like\n        `RequestValidityJson` but in seconds instead of days.\n      required:\n      - startTimestamp\n      - durationSeconds\n      properties:\n        durationSeconds:\n          type: string\n          description: Number of seconds the request remains valid. Decimal string.\n          example: '604800'\n        startTimestamp:\n          type: string\n          description: Unix timestamp (seconds) when this request becomes valid. Decimal string.\n          example: '1700000000'\n    Response:\n      type: object\n      required:\n      - fheKeyInfo\n      - crs\n      properties:\n        crs:\n          type: object\n          additionalProperties:\n            $ref: '#/components/schemas/KeyData'\n          propertyNames:\n            type: string\n        fheKeyInfo:\n          type: array\n          items:\n            $ref: '#/components/schemas/FheKeyInfo'\n    UserDecryptPostResponseJson:\n      type: object\n      required:\n      - status\n      - requestId\n      - result\n      properties:\n        requestId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n        result:\n          $ref: '#/components/schemas/UserDecryptQueuedResult'\n        status:\n          type: string\n          example: queued\n    UserDecryptQueuedResult:\n      type: object\n      required:\n      - jobId\n      properties:\n        jobId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n    UserDecryptRequestJson:\n      type: object\n      required:\n      - handleContractPairs\n      - requestValidity\n      - contractsChainId\n      - contractAddresses\n      - userAddress\n      - signature\n      - publicKey\n      - extraData\n      properties:\n        contractAddresses:\n          type: array\n          items:\n            type: string\n          example:\n          - \"0x1234567890123456789012345678901234567890\"\n          minItems: 1\n        contractsChainId:\n          $ref: '#/components/schemas/ChainId'\n        extraData:\n          type: string\n          description: Extra data forwarded verbatim to the gateway contract. Accepts `\"0x00\"`, version `0x01` (`0x01` + 32-byte contextId), or version `0x02` (`0x02` + 32-byte contextId + 32-byte epochId). contextId must be 0x07-tagged and epochId must be 0x08-tagged (first byte of each).\n          example: '0x00'\n        handleContractPairs:\n          type: array\n          items:\n            $ref: '#/components/schemas/HandleContractPairJson'\n        publicKey:\n          type: string\n          description: User's public key for re-encryption. Raw hex, no `0x` prefix, minimum 2 chars.\n          example: \"04b8e5d3f1a2c4e6d8f0a1b3c5d7e9f1a2b4c6d8e0f2a3b5c7d9e1f3a5b7c9d1\"\n        requestValidity:\n          $ref: '#/components/schemas/RequestValidityJson'\n        signature:\n          type: string\n          description: EIP-712 signature over the decryption request, signed by the user. Raw hex, 130 chars, no `0x` prefix.\n          example: \"aabbccdd00112233445566778899aabbccdd00112233445566778899aabbccdd00112233445566778899aabbccdd00112233445566778899aabbccdd0011223344\"\n        userAddress:\n          type: string\n          description: Ethereum address of the user requesting decryption. `0x` + 40 hex chars.\n          example: \"0x1234567890123456789012345678901234567890\"\n    UserDecryptResponseJson:\n      type: object\n      required:\n      - result\n      properties:\n        result:\n          type: array\n          items:\n            $ref: '#/components/schemas/UserDecryptResponsePayloadJson'\n    UserDecryptResponsePayloadJson:\n      type: object\n      required:\n      - payload\n      - signature\n      - extraData\n      properties:\n        extraData:\n          type: string\n        payload:\n          type: string\n          description: Re-encrypted share payload. Raw hex, no `0x` prefix.\n          example: \"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2\"\n        signature:\n          type: string\n          description: KMS signature over the payload. Raw hex, no `0x` prefix.\n          example: \"1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b\"\n    UserDecryptSucceededStatusResponse:\n      type: object\n      description: GET 200 — user decryption succeeded (has result, no error).\n      required:\n      - status\n      - requestId\n      - result\n      properties:\n        requestId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n        result:\n          $ref: '#/components/schemas/UserDecryptResponseJson'\n        status:\n          type: string\n          example: succeeded\n    V2ApiError:\n      type: object\n      description: Simple error body — used for 400 (no details), 404, 429, 500, and 503.\n      required:\n      - label\n      - message\n      properties:\n        label:\n          $ref: '#/components/schemas/V2ErrorLabel'\n          description: Machine-readable error label for client UX logic.\n        message:\n          type: string\n          description: Human-readable error message.\n          example: Internal server error\n    V2ApiErrorWithDetails:\n      type: object\n      description: Extended error body — used for 400 responses with field-level details.\n      required:\n      - label\n      - message\n      - details\n      properties:\n        details:\n          type: array\n          items:\n            $ref: '#/components/schemas/RelayerV2ErrorDetail'\n          description: Per-field validation issues.\n        label:\n          $ref: '#/components/schemas/V2ErrorLabel'\n          description: Machine-readable error label for client UX logic.\n        message:\n          type: string\n          description: Human-readable error message.\n          example: Request validation failed\n    V2ErrorLabel:\n      type: string\n      description: All machine-readable error labels the API can return.\n      enum:\n      - malformed_json\n      - missing_fields\n      - validation_failed\n      - request_error\n      - not_allowed_on_host_acl\n      - host_chain_id_not_supported\n      - not_found\n      - rate_limited\n      - internal_server_error\n      - host_acl_failed\n      - protocol_paused\n      - insufficient_balance\n      - insufficient_allowance\n      - gateway_not_reachable\n      - readiness_check_timed_out\n      - response_timed_out\n    V2ErrorResponseBody:\n      oneOf:\n      - $ref: '#/components/schemas/V2ApiErrorWithDetails'\n      - $ref: '#/components/schemas/V2ApiError'\n      description: |-\n        Union type for all V2 API error bodies.\n\n        Used as the concrete type for the `error` field in status and failed\n        responses. The `#[serde(untagged)]` attribute ensures the JSON output is\n        a flat `{label, message, ...}` object without a discriminator key.\n\n        **Deserialization order matters**: `WithDetails` is tried first so that\n        the `details` array is not silently dropped.\n    V2StatusFailed:\n      type: object\n      description: GET 4xx/5xx — request failed (no result, has error).\n      required:\n      - status\n      - requestId\n      - error\n      properties:\n        error:\n          $ref: '#/components/schemas/V2ErrorResponseBody'\n        requestId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n        status:\n          type: string\n          example: failed\n    V2StatusQueued:\n      type: object\n      description: GET 202 — request is still queued/processing (no result, no error).\n      required:\n      - status\n      - requestId\n      properties:\n        requestId:\n          type: string\n          example: 550e8400-e29b-41d4-a716-446655440000\n        status:\n          type: string\n          example: queued\n    VersionResponse:\n      type: object\n      required:\n      - name\n      - version\n      - build\n      properties:\n        build:\n          type: string\n          example: a1b2c3d4-clean\n        name:\n          type: string\n          example: fhevm-relayer\n        version:\n          type: string\n          example: 0.14.0\n  securitySchemes:\n    ApiKeyAuth:\n      type: apiKey\n      in: header\n      name: X-API-Key\nsecurity:\n- ApiKeyAuth: []\ntags:\n- name: Key URL\n  description: Read FHE public key URLs\n- name: Input Proof\n  description: Verify input proofs for encrypted computations\n- name: User Decrypt\n  description: Decrypt ciphertexts with user-provided key shares\n- name: Delegated User Decrypt\n  description: Decrypt ciphertexts via delegated key shares\n- name: User Decrypt v3\n  description: unified EIP-712 user-decryption (direct + delegated under one endpoint)\n- name: Public Decrypt\n  description: Decrypt ciphertexts using the network public key\n- name: Health\n  description: Liveness, readiness, and version probes\nx-tagGroups:\n- name: Key URL Endpoint\n  tags:\n  - Key URL\n- name: Ciphertext Operation Endpoints\n  tags:\n  - Input Proof\n  - User Decrypt\n  - Delegated User Decrypt\n  - Public Decrypt\n- name: Health Endpoints\n  tags:\n  - Health"}