{
  "openapi": "3.0.3",
  "info": {
    "title": "Anis Partner API",
    "version": "1.0.0",
    "description": "The API partners use to connect their own systems to Anis: read the catalogue, buy cards, and recover safely when an answer is lost.\n\n**Every request is signed and every answer is verified** (RFC 9421, ECDSA P-256). This file cannot express that — use an Anis SDK, or follow https://developers.anis.ly/docs/signing-requests.md exactly.\n\n**Before writing code, read the rules for AI assistants:** https://developers.anis.ly/agents/anis-partners/SKILL.md. The order rules decide whether a retry buys cards twice.\n\nDocumentation: https://developers.anis.ly/llms.txt · Error codes as data: https://developers.anis.ly/errors.json",
    "contact": {
      "name": "Anis",
      "email": "info@anis.ly",
      "url": "https://developers.anis.ly"
    }
  },
  "servers": [
    {
      "url": "https://{authority}",
      "description": "The address Anis gives you. Each deployment has its own address, keys and data.",
      "variables": {
        "authority": {
          "default": "partners.example",
          "description": "The address Anis gives you."
        }
      }
    }
  ],
  "security": [
    {
      "partnerMessageSignature": []
    }
  ],
  "paths": {
    "/v1/profile": {
      "get": {
        "operationId": "getPartnerProfile",
        "tags": [
          "profile"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Profile"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Read your profile",
        "description": "Your application’s identity, the Anis business account it acts for, and the permissions its current policy grants. Permissions are re-evaluated on every call, so read them rather than caching them.\n\n**Permission:** `profile:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Profile.GetAsync()`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/read-profile.md"
        }
      }
    },
    "/v1/wallets": {
      "get": {
        "operationId": "getPartnerWallets",
        "tags": [
          "wallets"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletCollection"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "List wallets",
        "description": "The wallets your application may use, with their balances. Pages with a cursor.\n\n**Permission:** `wallets:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Wallets.ListAsync()`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/list-wallets.md"
        }
      }
    },
    "/v1/wallets/{walletId}": {
      "get": {
        "operationId": "getPartnerWallet",
        "tags": [
          "wallets"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Wallet"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Read a wallet",
        "description": "One wallet and its balance.\n\n**Permission:** `wallets:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Wallets.GetAsync(walletId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/read-wallet.md"
        }
      }
    },
    "/v1/wallets/{walletId}/catalog/categories": {
      "get": {
        "operationId": "getPartnerCatalogueCategories",
        "tags": [
          "catalogue"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CatalogueCollection"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "List catalogue categories",
        "description": "The top level of the catalogue, as this wallet sees it. Pages with a cursor.\n\n**Permission:** `catalogue:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Catalogue.ListCategoriesAsync(walletId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/list-categories.md"
        }
      }
    },
    "/v1/wallets/{walletId}/catalog/categories/{categoryId}/subcategories": {
      "get": {
        "operationId": "getPartnerCatalogueCategorySubcategories",
        "tags": [
          "catalogue"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/CategoryId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CatalogueCollection"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "List subcategories of a category",
        "description": "The subcategories under one category. Pages with a cursor.\n\n**Permission:** `catalogue:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Catalogue.ListSubcategoriesAsync(walletId, categoryId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/list-subcategories.md"
        }
      }
    },
    "/v1/wallets/{walletId}/catalog/subcategories/{subcategoryId}": {
      "get": {
        "operationId": "getPartnerCatalogueSubcategory",
        "tags": [
          "catalogue"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/SubcategoryId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CatalogueObject"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Read a subcategory",
        "description": "One subcategory.\n\n**Permission:** `catalogue:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Catalogue.GetSubcategoryAsync(walletId, subcategoryId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/read-subcategory.md"
        }
      }
    },
    "/v1/wallets/{walletId}/catalog/subcategories/{subcategoryId}/cards": {
      "get": {
        "operationId": "getPartnerCatalogueSubcategoryCards",
        "tags": [
          "catalogue"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/SubcategoryId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/CatalogueCollection"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "List cards for sale",
        "description": "The cards of a subcategory that this wallet can buy, with the price this wallet pays. Pages with a cursor.\n- Send a card’s `unitPrice` as the order’s `expectedUnitPrice`. The other prices are for display.\n\n**Permission:** `catalogue:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Catalogue.ListCardsAsync(walletId, subcategoryId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/list-cards.md"
        }
      }
    },
    "/v1/wallets/{walletId}/orders": {
      "post": {
        "operationId": "createPartnerOrder",
        "tags": [
          "orders"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          },
          {
            "$ref": "#/components/parameters/Nonce"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOrderRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "boolean"
                },
                "description": "True when this answer repeats an order outcome already sent. It carries the order, never the card codes."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            },
            "description": "A resume’s answer. If it carries card codes, it is the first report of a completion whose first answer was lost — store them first. With `Idempotency-Replayed: true` it repeats an outcome already sent and carries no codes."
          },
          "201": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "Idempotency-Replayed": {
                "schema": {
                  "type": "boolean"
                },
                "description": "True when this answer repeats an order outcome already sent. It carries the order, never the card codes."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            },
            "description": "The order completed and this answer carries the card codes — store them first. With `Idempotency-Replayed: true` it repeats an outcome already sent and carries no codes."
          },
          "202": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              },
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            },
            "description": "Accepted — no outcome yet."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Refused: needs consent to use allowed debt."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Refused: conflicts with the current state."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Place an order",
        "description": "Buys cards from a wallet, under an operation id you choose and keep. The same id sent again never buys twice: it resumes the same order.\n- `201`: the order completed, and this answer carries the card codes. Store them first.\n- `200`: the answer a resume receives when the first answer was lost. If it carries card codes, it is the first time you see them — store them.\n- An answer marked `Idempotency-Replayed: true` repeats an order whose outcome was already sent: it carries the order, not the codes. If you never received that first answer — a timeout — the codes were in it: reveal them with the order’s invoice id, which needs `cards:reveal`.\n- `202`: accepted, no outcome yet. Send the same order again after `Retry-After`.\n\n**Permission:** `orders:create`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`replay_detected`](https://developers.anis.ly/errors/replay-detected), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`currency_not_supported`](https://developers.anis.ly/errors/currency-not-supported), [`idempotency_conflict`](https://developers.anis.ly/errors/idempotency-conflict), [`allowed_debt_consent_required`](https://developers.anis.ly/errors/allowed-debt-consent-required), [`insufficient_balance`](https://developers.anis.ly/errors/insufficient-balance), [`purchase_not_allowed`](https://developers.anis.ly/errors/purchase-not-allowed), [`purchase_not_allowed`](https://developers.anis.ly/errors/order-refused), [`business_subscription_required`](https://developers.anis.ly/errors/business-subscription-required), [`wallet_disabled`](https://developers.anis.ly/errors/wallet-disabled), [`wallet_expired`](https://developers.anis.ly/errors/wallet-expired), [`card_unavailable`](https://developers.anis.ly/errors/card-unavailable), [`quantity_unavailable`](https://developers.anis.ly/errors/quantity-unavailable), [`price_changed`](https://developers.anis.ly/errors/price-changed), [`owner_limit_exceeded`](https://developers.anis.ly/errors/owner-limit-exceeded), [`daily_limit_exceeded`](https://developers.anis.ly/errors/daily-limit-exceeded), [`operation_processing`](https://developers.anis.ly/errors/operation-processing), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Orders.CreateAsync(walletId, operationId, order)  /  ResumeAsync(...)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/create-order.md"
        }
      }
    },
    "/v1/orders/{operationId}": {
      "get": {
        "operationId": "getPartnerOrder",
        "tags": [
          "orders"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OperationId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            },
            "description": "Refused: not found, or not yours."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Read an order",
        "description": "Where an order stands. It reports state only: it never carries card codes and never moves an order forward — to recover an order, send it again.\n- Allowed with `orders:read`, or with `orders:create` for your own orders.\n\n**Permission:** `orders:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.Orders.GetAsync(operationId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/read-order.md"
        }
      }
    },
    "/v1/wallets/{walletId}/cards": {
      "get": {
        "operationId": "getPartnerOwnedCards",
        "tags": [
          "cards"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MaskedCardCollection"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "List owned cards",
        "description": "The cards a wallet has bought, with their codes hidden. Pages with a cursor.\n\n**Permission:** `cards:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.OwnedCards.ListAsync(walletId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/list-owned-cards.md"
        }
      }
    },
    "/v1/wallets/{walletId}/cards/{soldCardId}": {
      "get": {
        "operationId": "getPartnerOwnedCard",
        "tags": [
          "cards"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/SoldCardId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MaskedCard"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Read an owned card",
        "description": "One bought card, with its codes hidden.\n\n**Permission:** `cards:read`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`card_not_found`](https://developers.anis.ly/errors/card-not-found), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.OwnedCards.GetAsync(walletId, soldCardId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/read-owned-card.md"
        }
      }
    },
    "/v1/wallets/{walletId}/cards/{soldCardId}/reveal": {
      "post": {
        "operationId": "revealPartnerOwnedCard",
        "tags": [
          "cards"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/SoldCardId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          },
          {
            "$ref": "#/components/parameters/Nonce"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/RevealedCredential"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Reveal a card",
        "description": "Shows one bought card’s codes. Sends no body.\n\n**Permission:** `cards:reveal`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`replay_detected`](https://developers.anis.ly/errors/replay-detected), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`card_not_found`](https://developers.anis.ly/errors/card-not-found), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`reveal_not_allowed`](https://developers.anis.ly/errors/reveal-not-allowed), [`business_subscription_required`](https://developers.anis.ly/errors/business-subscription-required), [`wallet_disabled`](https://developers.anis.ly/errors/wallet-disabled), [`wallet_expired`](https://developers.anis.ly/errors/wallet-expired), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.OwnedCards.RevealAsync(walletId, soldCardId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/reveal-card.md"
        }
      }
    },
    "/v1/wallets/{walletId}/invoices/{invoiceId}/cards/reveal": {
      "post": {
        "operationId": "revealPartnerInvoiceCards",
        "tags": [
          "cards"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WalletId"
          },
          {
            "$ref": "#/components/parameters/InvoiceId"
          },
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          },
          {
            "$ref": "#/components/parameters/Nonce"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/RevealedCredentialCollection"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Reveal an invoice",
        "description": "Shows the codes of every card on an invoice — all of them or none, up to 100. Sends no body.\n\n**Permission:** `cards:reveal`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`replay_detected`](https://developers.anis.ly/errors/replay-detected), [`binding_not_authorized`](https://developers.anis.ly/errors/binding-not-authorized), [`account_inactive`](https://developers.anis.ly/errors/account-inactive), [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`reveal_not_allowed`](https://developers.anis.ly/errors/reveal-not-allowed), [`invoice_reveal_limit_exceeded`](https://developers.anis.ly/errors/invoice-reveal-limit-exceeded), [`business_subscription_required`](https://developers.anis.ly/errors/business-subscription-required), [`wallet_disabled`](https://developers.anis.ly/errors/wallet-disabled), [`wallet_expired`](https://developers.anis.ly/errors/wallet-expired), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `anis.OwnedCards.RevealInvoiceAsync(walletId, invoiceId)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/reveal-invoice.md"
        }
      }
    },
    "/v1/diagnostics/signature": {
      "post": {
        "operationId": "runPartnerSignatureDiagnostic",
        "tags": [
          "diagnostics"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/SignatureInput"
          },
          {
            "$ref": "#/components/parameters/Signature"
          },
          {
            "$ref": "#/components/parameters/ContentDigest"
          },
          {
            "$ref": "#/components/parameters/Nonce"
          },
          {
            "$ref": "#/components/parameters/AnisDate"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignatureDiagnostic"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Check your signature",
        "description": "The signature self-check: runs your call through Anis’s full checks and reports exactly what Anis saw — the method, address, path and query it signed over, the key it found and the permissions in force. It changes nothing. Sends exactly `{}`.\n- The right first call when a signature will not verify.\n\n**Permission:** `diagnostics:use`.\n**Refusals:** [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials), [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope), [`source_ip_not_allowed`](https://developers.anis.ly/errors/source-ip-not-allowed), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`replay_detected`](https://developers.anis.ly/errors/replay-detected), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`internal_error`](https://developers.anis.ly/errors/internal-error), [`request_timeout`](https://developers.anis.ly/errors/request-timeout).\n**.NET SDK:** `anis.Diagnostics.CheckSignatureAsync()`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/check-signature.md"
        }
      }
    },
    "/v1/enrollments/{invitationId}": {
      "get": {
        "operationId": "getPartnerEnrollment",
        "tags": [
          "enrollment"
        ],
        "security": [
          {
            "enrollmentToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/InvitationId"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentState"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Read an invitation",
        "description": "The invitation’s state and when it expires. Authorised with the enrolment token, not a signature.\n\n**Permission:** none.\n**Refusals:** [`invitation_invalid`](https://developers.anis.ly/errors/invitation-invalid), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `enrollment.GetAsync()`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/read-invitation.md"
        }
      }
    },
    "/v1/enrollments/{invitationId}/keys": {
      "post": {
        "operationId": "submitPartnerEnrollmentKey",
        "tags": [
          "enrollment"
        ],
        "security": [
          {
            "enrollmentToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/InvitationId"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentKeyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentKeyResult"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Submit a public key",
        "description": "Sends the PUBLIC half of a new P-256 key, and receives the challenge to prove you hold the private half.\n- Save the private key before you call this: an invitation takes exactly one key.\n\n**Permission:** none.\n**Refusals:** [`invitation_invalid`](https://developers.anis.ly/errors/invitation-invalid), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`key_proof_invalid`](https://developers.anis.ly/errors/key-proof-invalid), [`key_duplicate`](https://developers.anis.ly/errors/key-duplicate), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `enrollment.SubmitKeyAsync(request)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/submit-key.md"
        }
      }
    },
    "/v1/enrollments/{invitationId}/proof": {
      "post": {
        "operationId": "submitPartnerEnrollmentProof",
        "tags": [
          "enrollment"
        ],
        "security": [
          {
            "enrollmentToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/InvitationId"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentProofRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentStatus"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableRequestModel"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Prove you hold the key",
        "description": "Sends the proof of possession. Once accepted, the key waits for Anis staff to record its fingerprint and confirm it.\n- A proof that does not verify, or comes more than about 30 minutes after the key submission, is not refused: the answer says `proofState: \"failed\"`. Check for `\"accepted\"`.\n- After five failed proofs, further proofs are refused as `rate_limited` until Anis staff restart the enrolment.\n\n**Permission:** none.\n**Refusals:** [`invitation_invalid`](https://developers.anis.ly/errors/invitation-invalid), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`validation_failed`](https://developers.anis.ly/errors/validation-failed), [`challenge_expired`](https://developers.anis.ly/errors/challenge-expired), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `enrollment.ProveAsync(submitted, key)`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/submit-proof.md"
        }
      }
    },
    "/v1/enrollments/{invitationId}/status": {
      "get": {
        "operationId": "getPartnerEnrollmentStatus",
        "tags": [
          "enrollment"
        ],
        "security": [
          {
            "enrollmentToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/InvitationId"
          },
          {
            "$ref": "#/components/parameters/AcceptLanguage"
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/XRequestId"
              },
              "Content-Digest": {
                "$ref": "#/components/headers/ContentDigest"
              },
              "Signature-Input": {
                "$ref": "#/components/headers/SignatureInput"
              },
              "Signature": {
                "$ref": "#/components/headers/Signature"
              },
              "Cache-Control": {
                "$ref": "#/components/headers/CacheControl"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentStatus"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/DependencyUnavailable"
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Read enrolment status",
        "description": "Where the key stands: waiting for proof, waiting for Anis staff, active, or no longer available.\n\n**Permission:** none.\n**Refusals:** [`invitation_invalid`](https://developers.anis.ly/errors/invitation-invalid), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found), [`rate_limited`](https://developers.anis.ly/errors/rate-limited), [`dependency_unavailable`](https://developers.anis.ly/errors/dependency-unavailable), [`request_timeout`](https://developers.anis.ly/errors/request-timeout), [`internal_error`](https://developers.anis.ly/errors/internal-error).\n**.NET SDK:** `enrollment.GetStatusAsync()`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/read-enrollment-status.md"
        }
      }
    },
    "/.well-known/partner-signing-keys.json": {
      "get": {
        "operationId": "getPartnerSigningKeys",
        "tags": [
          "signing-keys"
        ],
        "security": [],
        "responses": {
          "200": {
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                },
                "description": "How long this answer may be cached."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SigningKeySet"
                }
              }
            },
            "description": "Success."
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "summary": "Anis’s public signing keys",
        "description": "Every public key that may sign Anis’s answers — including the next one before a rotation and the previous one after it. The only route that needs no signature. Clients cache it and fetch it again when an answer names a key they have not seen.\n\n**Permission:** none.\n**Refusals:** .\n**.NET SDK:** `Fetched and cached by the SDK`",
        "externalDocs": {
          "url": "https://developers.anis.ly/reference/signing-keys.md"
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "partnerMessageSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "Signature",
        "description": "An RFC 9421 HTTP message signature made with your enrolled key: `Signature` and `Signature-Input`, plus the headers each route's kind of signed call needs. OpenAPI cannot describe it fully — use an Anis SDK, or follow https://developers.anis.ly/docs/signing-requests.md and test against https://developers.anis.ly/docs/test-vectors.md."
      },
      "enrollmentToken": {
        "type": "http",
        "scheme": "Enrollment",
        "description": "Authorised with `Authorization: Enrollment <token>`; not signed. The token comes with the invitation from Anis staff and is valid until the invitation expires."
      }
    },
    "parameters": {
      "WalletId": {
        "name": "walletId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "The wallet, a UUID in lower case with hyphens."
      },
      "CategoryId": {
        "name": "categoryId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "A catalogue category, as returned by the catalogue."
      },
      "SubcategoryId": {
        "name": "subcategoryId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "A catalogue subcategory, as returned by the catalogue."
      },
      "SoldCardId": {
        "name": "soldCardId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "A card you bought, as returned in your owned cards."
      },
      "InvoiceId": {
        "name": "invoiceId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "The invoice id of an order, as returned with the order."
      },
      "OperationId": {
        "name": "operationId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "The operation id you chose for the order."
      },
      "InvitationId": {
        "name": "invitationId",
        "in": "path",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "The invitation id Anis staff gave you."
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "The `nextCursor` of the previous page, passed back exactly as received. Leave it out for the first page."
      },
      "SignatureInput": {
        "name": "Signature-Input",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The signed parts and parameters of your RFC 9421 signature, label `sig1`. On changes and orders it ends with `;nonce=\"<the Nonce header>\"`. See https://developers.anis.ly/docs/signing-requests.md."
      },
      "Signature": {
        "name": "Signature",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "`sig1=:<base64>:` — ECDSA P-256 with SHA-256, in the 64-byte form (r then s), never DER."
      },
      "ContentDigest": {
        "name": "Content-Digest",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "`sha-256=:<base64>:` over the exact bytes of the body you send. A reveal sends no body, so it digests zero bytes: `sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:`."
      },
      "Nonce": {
        "name": "Nonce",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "A new random value for every attempt, including a resume. It must equal the `nonce` parameter of `Signature-Input`."
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/Uuid"
        },
        "description": "Your operation id: a UUID you choose once per purchase and store with the order BEFORE sending. Send it again, unchanged, on every resume — a new id can buy the cards a second time."
      },
      "AnisDate": {
        "name": "X-Anis-Date",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The time you signed, ISO-8601 UTC, such as `2026-09-19T08:00:00Z`."
      },
      "AcceptLanguage": {
        "name": "Accept-Language",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "ar",
            "en"
          ]
        },
        "description": "The language of the text written for people, such as a refusal’s `title` and `detail`."
      }
    },
    "headers": {
      "XRequestId": {
        "schema": {
          "type": "string"
        },
        "description": "The id of this call. Quote it when you ask Anis about it. Signed."
      },
      "ContentDigest": {
        "schema": {
          "type": "string"
        },
        "description": "The digest of the exact bytes of this answer. Check it BEFORE the signature."
      },
      "SignatureInput": {
        "schema": {
          "type": "string"
        },
        "description": "The parts Anis signed this answer over, bound to your request by `;req`. Rebuild the list yourself; never trust it as given."
      },
      "Signature": {
        "schema": {
          "type": "string"
        },
        "description": "Anis’s signature over this answer. Verify it against Anis’s published keys and throw away any answer that fails: https://developers.anis.ly/docs/verifying-answers.md."
      },
      "Location": {
        "schema": {
          "type": "string"
        },
        "description": "The address of the order."
      },
      "RetryAfter": {
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "description": "Seconds to wait before sending the same request again."
      },
      "CacheControl": {
        "schema": {
          "type": "string"
        },
        "description": "Caching instructions for this answer. Signed when present."
      }
    },
    "responses": {
      "Problem": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        },
        "description": "A refusal: a signed problem. Branch on its `code`."
      },
      "Unauthorized": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        },
        "description": "Refused: not authenticated."
      },
      "Forbidden": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        },
        "description": "Refused: not allowed."
      },
      "NotFound": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        },
        "description": "Refused: not found, or not yours."
      },
      "Conflict": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        },
        "description": "Refused: conflicts with the current state."
      },
      "UnprocessableRequestModel": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        },
        "description": "Refused: the request breaks a rule."
      },
      "RateLimited": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        },
        "description": "Refused: a limit was reached."
      },
      "DependencyUnavailable": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        },
        "description": "No decision: a dependency was unavailable."
      },
      "CatalogueCollection": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/CatalogueCollection"
            }
          }
        },
        "description": "A page of the catalogue."
      },
      "CatalogueObject": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/CatalogueObject"
            }
          }
        },
        "description": "One catalogue item."
      },
      "RevealedCredential": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControl"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RevealedCredential"
            }
          }
        },
        "description": "The codes of one card. Store them as secrets; never log them."
      },
      "RevealedCredentialCollection": {
        "headers": {
          "X-Request-Id": {
            "$ref": "#/components/headers/XRequestId"
          },
          "Content-Digest": {
            "$ref": "#/components/headers/ContentDigest"
          },
          "Signature-Input": {
            "$ref": "#/components/headers/SignatureInput"
          },
          "Signature": {
            "$ref": "#/components/headers/Signature"
          },
          "Cache-Control": {
            "$ref": "#/components/headers/CacheControl"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RevealedCredentialCollection"
            }
          }
        },
        "description": "The codes of every card of the invoice. Store them as secrets; never log them."
      }
    },
    "schemas": {
      "Uuid": {
        "type": "string",
        "format": "uuid"
      },
      "Money": {
        "type": "object",
        "required": [
          "amount",
          "currency"
        ],
        "properties": {
          "amount": {
            "type": "string",
            "pattern": "^-?[0-9]+\\.[0-9]{3}$",
            "description": "A decimal string with exactly three decimals, such as `\"10.500\"` — never a JSON number."
          },
          "currency": {
            "type": "string",
            "description": "The currency code, such as `LYD`: always the wallet’s currency."
          },
          "asOf": {
            "type": "string",
            "format": "date-time",
            "description": "When this price or balance was read."
          }
        }
      },
      "LocalizedText": {
        "type": "object",
        "properties": {
          "ar": {
            "type": "string",
            "description": "The Arabic text."
          },
          "en": {
            "type": "string",
            "description": "The English text."
          }
        }
      },
      "EmptyBody": {
        "type": "object",
        "additionalProperties": false
      },
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "The address of this error’s page on this site. Permanent."
          },
          "title": {
            "type": "string",
            "description": "A short title for people, in the language you asked for. Do not branch on it."
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status, repeated in the body."
          },
          "code": {
            "type": "string",
            "description": "The machine code — the one to branch on. See [Error codes](https://developers.anis.ly/errors)."
          },
          "detail": {
            "type": "string",
            "description": "An explanation for people, in the language you asked for. Do not branch on it."
          },
          "requestId": {
            "type": "string",
            "description": "The id to quote when you ask Anis about this call."
          },
          "extensions": {
            "type": "object",
            "additionalProperties": true,
            "description": "Extra members some codes document on their page."
          }
        }
      },
      "Profile": {
        "type": "object",
        "required": [
          "partner",
          "application"
        ],
        "properties": {
          "partner": {
            "type": "object",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "description": "The partner’s id."
              }
            },
            "description": "The partner your application belongs to."
          },
          "application": {
            "type": "object",
            "required": [
              "id",
              "scopes"
            ],
            "properties": {
              "id": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "description": "Your application’s id. It stays the same when your keys are replaced."
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "The permissions your application has right now. Re-read rather than cache: a change applies to your next call."
              }
            },
            "description": "Your application."
          },
          "ownerAccount": {
            "type": "object",
            "properties": {
              "id": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "description": "The business account’s id."
              },
              "displayName": {
                "type": "string",
                "description": "The business account’s name."
              }
            },
            "description": "The Anis business account your application acts for, when shown."
          },
          "documentationVersion": {
            "type": "string",
            "description": "The version of this documentation the Anis deployment you called matches."
          }
        }
      },
      "Wallet": {
        "type": "object",
        "required": [
          "id",
          "name",
          "currency",
          "balance"
        ],
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The wallet’s id. Every wallet-level call takes it in the address."
          },
          "name": {
            "type": "string",
            "description": "The wallet’s name."
          },
          "currency": {
            "type": "string",
            "description": "The currency the wallet holds and buys in."
          },
          "balance": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "description": "The balance you can spend now, with the moment it was read."
          }
        }
      },
      "WalletCollection": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Wallet"
            },
            "description": "The wallets on this page."
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass it as `cursor` to get the next page. Absent on the last page."
          }
        }
      },
      "CatalogueObject": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/CatalogueCategory"
          },
          {
            "$ref": "#/components/schemas/CatalogueSubcategory"
          },
          {
            "$ref": "#/components/schemas/CatalogueCard"
          }
        ]
      },
      "CatalogueCategory": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "inStock",
          "displayOrder"
        ],
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The category’s id."
          },
          "name": {
            "allOf": [
              {
                "$ref": "#/components/schemas/LocalizedText"
              }
            ],
            "description": "The category’s name, in Arabic and English."
          },
          "description": {
            "allOf": [
              {
                "$ref": "#/components/schemas/LocalizedText"
              }
            ],
            "description": "A description, in Arabic and English."
          },
          "logo": {
            "type": "string",
            "nullable": true,
            "description": "The address of the category’s logo image."
          },
          "type": {
            "type": "string",
            "nullable": true,
            "enum": [
              "local",
              "international",
              null
            ],
            "description": "Whether the category is local or international."
          },
          "inStock": {
            "type": "boolean",
            "description": "Whether anything in it can be bought now."
          },
          "displayOrder": {
            "type": "integer",
            "description": "The order to show categories in — lower first."
          }
        }
      },
      "CatalogueSubcategory": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "categoryId",
          "isBestSelling",
          "displayOrder",
          "available"
        ],
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The subcategory’s id."
          },
          "categoryId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The category it belongs to."
          },
          "name": {
            "allOf": [
              {
                "$ref": "#/components/schemas/LocalizedText"
              }
            ],
            "description": "The subcategory’s name, in Arabic and English."
          },
          "description": {
            "allOf": [
              {
                "$ref": "#/components/schemas/LocalizedText"
              }
            ],
            "description": "A description, in Arabic and English."
          },
          "logo": {
            "type": "string",
            "nullable": true,
            "description": "The address of the subcategory’s logo image."
          },
          "isBestSelling": {
            "type": "boolean",
            "description": "Marked by Anis as a best seller."
          },
          "displayOrder": {
            "type": "integer",
            "description": "The order to show subcategories in — lower first."
          },
          "available": {
            "type": "boolean",
            "description": "Whether it can be bought from now."
          }
        }
      },
      "CatalogueCard": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "subcategoryId",
          "hasSpecialOffer",
          "available"
        ],
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The card’s id — the `cardId` an order carries."
          },
          "subcategoryId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The subcategory it belongs to."
          },
          "name": {
            "allOf": [
              {
                "$ref": "#/components/schemas/LocalizedText"
              }
            ],
            "description": "The card’s name, in Arabic and English."
          },
          "faceValue": {
            "type": "string",
            "nullable": true,
            "description": "The value printed on the card, when it has one."
          },
          "unitPrice": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "description": "The price THIS wallet pays. Send it unchanged as the order’s `expectedUnitPrice`. A card without it cannot be sold to this wallet."
          },
          "businessPrice": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "description": "For display. An order at this price can be refused as `price_changed`."
          },
          "personalPrice": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "description": "The retail price, shown only while it is above the business price. For display."
          },
          "hasSpecialOffer": {
            "type": "boolean",
            "description": "Whether a special offer applies."
          },
          "specialOfferPrice": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "description": "The offer price, shown only with a special offer. For display."
          },
          "available": {
            "type": "boolean",
            "description": "Whether the card can be bought now."
          }
        }
      },
      "CatalogueCollection": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogueObject"
            },
            "description": "The categories, subcategories or cards on this page — each list route returns one kind."
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass it as `cursor` to get the next page. Absent on the last page."
          }
        }
      },
      "CreateOrderRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "cardId",
          "quantity",
          "expectedUnitPrice",
          "expectedTotal"
        ],
        "properties": {
          "externalReference": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Your own reference, 1 to 100 characters: Latin letters and digits, space and `- _ . : / #`."
          },
          "cardId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The catalogue card to buy."
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "description": "At least 1 and at most the per-order maximum (100 by default), and within the card’s own minimum and maximum."
          },
          "expectedUnitPrice": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "description": "The card’s `unitPrice` exactly as the catalogue showed it for this wallet."
          },
          "expectedTotal": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "description": "`expectedUnitPrice` times `quantity`, exactly — computed without floating point."
          },
          "useAllowedDebt": {
            "type": "boolean",
            "default": false,
            "description": "Set to `true` only if you consent to use the account’s allowed debt. Defaults to `false` and is never switched on for you."
          }
        }
      },
      "Order": {
        "type": "object",
        "required": [
          "operationId",
          "status"
        ],
        "properties": {
          "operationId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The operation id you chose and sent as `Idempotency-Key`."
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "recoveryExhausted",
              "completed",
              "failed"
            ],
            "description": "`processing`: accepted, no outcome yet. `completed`: bought. `failed`: refused by a business rule, nothing bought. `recoveryExhausted`: Anis could not learn the outcome yet — it may have completed; keep resuming slowly and tell Anis."
          },
          "invoiceId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The invoice the cards are on. Use it to reveal them again later."
          },
          "walletId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The wallet the order was paid from."
          },
          "cardId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The catalogue card bought."
          },
          "quantity": {
            "type": "integer",
            "description": "How many cards."
          },
          "total": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Money"
              }
            ],
            "description": "What the order cost."
          },
          "soldCards": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RevealedCredential"
            },
            "description": "The card codes. Present only on the answer that FIRST reports the order completed — store them before anything else."
          },
          "completedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the order completed."
          }
        }
      },
      "MaskedCard": {
        "type": "object",
        "required": [
          "id",
          "credentialAvailable"
        ],
        "properties": {
          "id": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The sold card’s id — what revealing one card takes."
          },
          "orderOperationId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The operation id of the order that bought it."
          },
          "invoiceId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The invoice it is on — what revealing a whole invoice takes."
          },
          "card": {
            "type": "object",
            "properties": {
              "id": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Uuid"
                  }
                ],
                "description": "The catalogue card’s id."
              },
              "name": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/LocalizedText"
                  }
                ],
                "description": "The catalogue card’s name, in Arabic and English."
              }
            },
            "description": "The catalogue card it was sold from."
          },
          "serialNumberMasked": {
            "type": "string",
            "description": "The serial number, partly hidden. The full codes come only from a reveal."
          },
          "credentialAvailable": {
            "type": "boolean",
            "description": "Whether this card’s codes can be revealed."
          },
          "purchasedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was bought."
          }
        }
      },
      "MaskedCardCollection": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MaskedCard"
            },
            "description": "The owned cards on this page."
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Pass it as `cursor` to get the next page. Absent on the last page."
          }
        }
      },
      "RevealedCredential": {
        "type": "object",
        "required": [
          "soldCardId"
        ],
        "properties": {
          "soldCardId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The sold card these codes belong to."
          },
          "serialNumber": {
            "type": "string",
            "description": "The card’s serial number. A secret: store it where you keep secrets and never log it."
          },
          "voucher": {
            "type": "string",
            "description": "The card’s voucher code. A secret: store it where you keep secrets and never log it."
          },
          "revealedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was revealed."
          }
        }
      },
      "RevealedCredentialCollection": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/RevealedCredential"
            },
            "description": "Every card on the invoice with its codes — all of them or none, at most 100."
          }
        }
      },
      "SignatureDiagnostic": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "routeId",
          "method",
          "authority",
          "path",
          "canonicalQuery",
          "requestKind",
          "requiredScope",
          "coveredComponents",
          "keyId",
          "partnerId",
          "applicationId",
          "policyVersion",
          "effectiveScopes",
          "receivedAt"
        ],
        "properties": {
          "routeId": {
            "type": "string",
            "description": "The route Anis matched your call to."
          },
          "method": {
            "type": "string",
            "description": "The method, as Anis saw it."
          },
          "authority": {
            "type": "string",
            "description": "The host (and port, if not the default), as Anis saw it — lower-cased."
          },
          "path": {
            "type": "string",
            "description": "The path, as Anis saw it."
          },
          "canonicalQuery": {
            "type": "string",
            "description": "The query, as Anis saw it, without its leading `?`."
          },
          "requestKind": {
            "type": "string",
            "enum": [
              "safeRead",
              "bodylessNonceMutation",
              "orderMutation",
              "enrollmentToken",
              "public"
            ],
            "description": "How Anis expects this route to be signed."
          },
          "requiredScope": {
            "type": "string",
            "description": "The permission this route needs."
          },
          "coveredComponents": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The signed components this route requires, in order."
          },
          "keyId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The key id Anis found your signature under."
          },
          "partnerId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The partner that key belongs to."
          },
          "applicationId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The application that key belongs to."
          },
          "policyVersion": {
            "type": "integer",
            "description": "The version of your application’s permissions that applied. It goes up each time Anis staff change them."
          },
          "effectiveScopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The permissions in force for this call."
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When Anis received the call."
          }
        }
      },
      "EnrollmentState": {
        "type": "object",
        "properties": {
          "invitationId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The invitation."
          },
          "applicationId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The application being enrolled."
          },
          "state": {
            "type": "string",
            "description": "`pendingInvitation`, `pendingPublicKey`, `pendingProof`, `pendingApproval`, `active` or `unavailable`."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the invitation expires — about a day after it is issued, by default."
          }
        }
      },
      "PublicJwk": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "kty",
          "crv",
          "x",
          "y"
        ],
        "properties": {
          "kty": {
            "type": "string",
            "enum": [
              "EC"
            ],
            "description": "Always `EC`."
          },
          "crv": {
            "type": "string",
            "enum": [
              "P-256"
            ],
            "description": "Always `P-256`."
          },
          "x": {
            "type": "string",
            "description": "The key’s x coordinate: exactly 32 bytes, base64url without padding."
          },
          "y": {
            "type": "string",
            "description": "The key’s y coordinate: exactly 32 bytes, base64url without padding."
          },
          "kid": {
            "type": "string",
            "description": "In Anis’s signing keys: the key an answer’s signature names. Treat it as an opaque name. Not sent when you submit your own key."
          },
          "use": {
            "type": "string",
            "description": "Intended use, when published."
          },
          "alg": {
            "type": "string",
            "description": "Algorithm, when published."
          }
        }
      },
      "EnrollmentKeyRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "publicJwk",
          "notBefore",
          "expiresAt"
        ],
        "properties": {
          "publicJwk": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PublicJwk"
              }
            ],
            "description": "The PUBLIC half of a new P-256 key only. A private member is refused."
          },
          "notBefore": {
            "type": "string",
            "format": "date-time",
            "description": "Only the length of the window (to `expiresAt`) is used — kept between 1 day and 2 years by default — and it starts when Anis staff activate the key."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "The end of the validity you ask for. See `notBefore`."
          },
          "cidrs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The networks you will call from, proposed for Anis staff to confirm."
          }
        }
      },
      "EnrollmentKeyResult": {
        "type": "object",
        "required": [
          "keyId",
          "thumbprint",
          "challenge"
        ],
        "properties": {
          "keyId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "Your key id: the `keyid` every signature will carry once the key is active."
          },
          "thumbprint": {
            "type": "string",
            "description": "The key’s fingerprint. Give it to Anis staff through the channel you agreed; they confirm the key with it."
          },
          "challenge": {
            "type": "string",
            "description": "The challenge your proof answers. It is returned only here: keep it until the proof is accepted."
          },
          "challengeGeneration": {
            "type": "integer",
            "description": "Which challenge this is; a restarted enrolment issues the next one."
          }
        }
      },
      "EnrollmentProofRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "keyId",
          "challengeGeneration",
          "signature"
        ],
        "properties": {
          "keyId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "The key id from the key submission."
          },
          "challengeGeneration": {
            "type": "integer",
            "description": "The challenge generation you are answering."
          },
          "signature": {
            "type": "string",
            "description": "ECDSA P-256/SHA-256 over the proof message, 64 bytes (not DER), base64url without padding."
          }
        }
      },
      "EnrollmentStatus": {
        "type": "object",
        "properties": {
          "keyId": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Uuid"
              }
            ],
            "description": "Your key id."
          },
          "challengeGeneration": {
            "type": "integer",
            "description": "The current challenge generation."
          },
          "proofState": {
            "type": "string",
            "description": "`pending`, `accepted` or `failed` — a proof that did not verify or came too late. After five failed proofs, ask Anis staff to restart the enrolment."
          },
          "approvalState": {
            "type": "string",
            "description": "`pending` while Anis staff have not confirmed the key, `approved` once it is active, `notApplicable` otherwise."
          },
          "state": {
            "type": "string",
            "description": "`pendingProof`, `pendingApproval`, `active` — the key signs requests — or `unavailable` (revoked, expired or replaced)."
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the current step expires."
          }
        }
      },
      "SigningKeySet": {
        "type": "object",
        "required": [
          "keys"
        ],
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicJwk"
            },
            "description": "Every public key that may sign an answer — including the next one before a rotation and the previous one after it."
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Anis developer documentation",
    "url": "https://developers.anis.ly"
  }
}
