{"language":"en","source":"https://developers.anis.ly/errors","howToUse":"Branch on `code`, never on `title` or `detail`. `sendAgainUnchanged`: whether the same request may simply be sent again. `orderPlaced` answers, for an order: \"no\" — this request bought nothing; \"unknown\" — the order may still complete, so resume it with the SAME operation id; null — this code never answers an order. `sentToday: false` marks a reserved code Anis does not send.","errors":[{"code":"invalid_credentials","status":401,"type":"https://developers.anis.ly/errors/invalid-credentials","page":"https://developers.anis.ly/errors/invalid-credentials.md","title":"Invalid credentials","area":"signing","areaTitle":"Keys and signatures","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"Anis could not authenticate the call: the key id is unknown, the key is not active (not yet confirmed, revoked or expired), the signature does not match the request, the signature is too old or signed on a clock that is out, or the body does not match its `Content-Digest`. All of these get this same answer on purpose, so a refusal never tells anyone which one to work around.","whatToDo":["Check that the key id and the private key you sign with belong together.","Check that the key is active: the enrolment status reports `active` once Anis staff confirm it.","Check your server clock, and sign each attempt afresh — never reuse an old signature.","Compute the `Content-Digest` over the exact bytes you send.","Run the signature self-check: it reports exactly what Anis saw. If the self-check is refused too, the key itself is the problem."],"dotnetException":"InvalidCredentialsException"},{"code":"signature_expired","status":401,"type":"https://developers.anis.ly/errors/signature-expired","page":"https://developers.anis.ly/errors/signature-expired.md","title":"Signature expired","area":"signing","areaTitle":"Keys and signatures","sentToday":false,"sendAgainUnchanged":true,"orderPlaced":"no","meaning":"Reserved. Anis does not send this code today: a signature that is too old, or signed on a clock that is out, is answered `invalid_credentials` — on purpose, so a refusal never says which part of a signature failed.","whatToDo":["Handle it like [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials) if you ever receive it.","Keep your server clock synchronised (NTP), and sign every attempt afresh."],"dotnetException":"InvalidCredentialsException"},{"code":"invalid_content_digest","status":400,"type":"https://developers.anis.ly/errors/invalid-content-digest","page":"https://developers.anis.ly/errors/invalid-content-digest.md","title":"Invalid content digest","area":"signing","areaTitle":"Keys and signatures","sentToday":false,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"Reserved. Anis does not send this code today: a body that does not match its `Content-Digest` is answered `invalid_credentials`.","whatToDo":["Handle it like [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials) if you ever receive it.","Compute the digest over the exact bytes you send, and check that no proxy re-encodes request bodies."],"dotnetException":"AnisApiException"},{"code":"replay_detected","status":409,"type":"https://developers.anis.ly/errors/replay-detected","page":"https://developers.anis.ly/errors/replay-detected.md","title":"Replay detected","area":"signing","areaTitle":"Keys and signatures","sentToday":true,"sendAgainUnchanged":true,"orderPlaced":"unknown","meaning":"The request reused a nonce your application had already used. The SDKs make a fresh nonce for every attempt, so this usually means something between you and Anis — a proxy, a load balancer or an automatic retry — sent the same request twice. This copy was refused; the copy that arrived first may have been processed.","whatToDo":["On an order: the first copy may have bought the cards. Resume with the SAME operation id and the same body — never a new id.","On any other call: send it again. A new signature carries a new nonce.","Find what re-sends your requests and switch it off for Anis calls."],"dotnetException":"ReplayDetectedException"},{"code":"source_ip_not_allowed","status":403,"type":"https://developers.anis.ly/errors/source-ip-not-allowed","page":"https://developers.anis.ly/errors/source-ip-not-allowed.md","title":"Source address not allowed","area":"access","areaTitle":"Permissions and account","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"Anis’s own network protection refused the address the call came from. This is not about your application’s allowed networks — a call from outside those is answered `insufficient_scope`.","whatToDo":["Contact Anis with the request id."],"dotnetException":"AuthorizationException"},{"code":"insufficient_scope","status":403,"type":"https://developers.anis.ly/errors/insufficient-scope","page":"https://developers.anis.ly/errors/insufficient-scope.md","title":"Insufficient scope","area":"access","areaTitle":"Permissions and account","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"Your application may not make this call: its permissions do not include the one this route needs, or the call came from an address outside the application’s allowed networks. Both get this same answer on purpose.","whatToDo":["Read your profile: it lists the permissions your application has right now.","Check that you call from one of the networks agreed with Anis.","Ask Anis staff to change either; the change applies to your next call."],"dotnetException":"AuthorizationException"},{"code":"binding_not_authorized","status":403,"type":"https://developers.anis.ly/errors/binding-not-authorized","page":"https://developers.anis.ly/errors/binding-not-authorized.md","title":"Account not authorised","area":"access","areaTitle":"Permissions and account","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The Anis business account behind your application is not in a state that allows partner access — for example it is not an active account with a Business subscription.","whatToDo":["Contact Anis to restore the account; retrying does not help until then."],"dotnetException":"AuthorizationException"},{"code":"resource_not_found","status":404,"type":"https://developers.anis.ly/errors/resource-not-found","page":"https://developers.anis.ly/errors/resource-not-found.md","title":"Not found","area":"request","areaTitle":"The request itself","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"What you asked for does not exist, or it is not yours. Both get the same answer on purpose — for example an order id that belongs to another application looks exactly like one that was never used.","whatToDo":["Check the id. For an order, use the operation id you sent when you placed it."],"dotnetException":"ResourceNotFoundException"},{"code":"card_not_found","status":404,"type":"https://developers.anis.ly/errors/card-not-found","page":"https://developers.anis.ly/errors/card-not-found.md","title":"Card not found","area":"request","areaTitle":"The request itself","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The sold card is not in this wallet, or it is not yours. Both get the same answer.","whatToDo":["Check the sold-card id and the wallet it was bought from; the owned-cards list shows both."],"dotnetException":"ResourceNotFoundException"},{"code":"wallet_not_granted","status":404,"type":"https://developers.anis.ly/errors/wallet-not-granted","page":"https://developers.anis.ly/errors/wallet-not-granted.md","title":"Wallet not granted","area":"request","areaTitle":"The request itself","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The wallet in the address is not granted to your application — or does not exist. Both get the same answer, so the refusal never reveals which wallets exist.","whatToDo":["Use a wallet id from the wallets list, which shows exactly the wallets your application may use.","Ask Anis staff to grant the wallet if you need it."],"dotnetException":"ResourceNotFoundException"},{"code":"validation_failed","status":422,"type":"https://developers.anis.ly/errors/validation-failed","page":"https://developers.anis.ly/errors/validation-failed.md","title":"Validation failed","area":"request","areaTitle":"The request itself","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The request broke a rule of the API. The answer never names the field, on purpose, so it cannot be used to probe for valid ids or prices.","whatToDo":["Prices must be decimal strings with exactly three decimals, and the total must be the unit price times the quantity, exactly.","`externalReference` must be 1 to 100 characters: Latin letters and digits, space and `- _ . : / #`.","Pass a paging cursor back exactly as received.","A reveal takes no body at all; the signature self-check takes exactly `{}`."],"dotnetException":"ValidationFailedException"},{"code":"idempotency_conflict","status":409,"type":"https://developers.anis.ly/errors/idempotency-conflict","page":"https://developers.anis.ly/errors/idempotency-conflict.md","title":"Operation id already used","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"This operation id was already used with a DIFFERENT order body. This request was not placed. The order stored under that id is untouched — and if you were resuming it, it may have completed.","whatToDo":["If you meant to resume: send exactly the body you stored with that id — same card, quantity, prices and reference.","If this is a genuinely new purchase: use a new operation id.","One id must always mean one purchase with one body."],"dotnetException":"IdempotencyConflictException"},{"code":"operation_processing","status":202,"type":"https://developers.anis.ly/errors/operation-processing","page":"https://developers.anis.ly/errors/operation-processing.md","title":"Order still processing","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":true,"orderPlaced":"unknown","meaning":"The order was accepted and has no outcome yet.","whatToDo":["Wait for the time in `Retry-After`, then send the SAME order again — same operation id, same body. That is what moves it forward.","Reading the order’s status shows where it stands, but does not move it forward.","Never place it again under a new id: that can buy the cards twice."],"dotnetException":"OrderProcessing (a result, not an exception)"},{"code":"allowed_debt_consent_required","status":402,"type":"https://developers.anis.ly/errors/allowed-debt-consent-required","page":"https://developers.anis.ly/errors/allowed-debt-consent-required.md","title":"Allowed-debt consent required","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The wallet can cover this purchase only by using the account’s allowed debt, and the order did not consent to that. Debt is never used without an explicit yes.","whatToDo":["Place a new order with `useAllowedDebt: true` — only if you mean to spend debt — under a new operation id."],"dotnetException":"AnisApiException"},{"code":"insufficient_balance","status":409,"type":"https://developers.anis.ly/errors/insufficient-balance","page":"https://developers.anis.ly/errors/insufficient-balance.md","title":"Insufficient balance","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The wallet cannot cover the purchase. Nothing was charged, and the order is closed: sending the same operation id again returns this same answer.","whatToDo":["Top up the wallet, then place a new order with a new operation id."],"dotnetException":"InsufficientBalanceException"},{"code":"purchase_not_allowed","status":403,"type":"https://developers.anis.ly/errors/purchase-not-allowed","page":"https://developers.anis.ly/errors/purchase-not-allowed.md","title":"Purchase not allowed","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"A rule on the Anis business account forbids this purchase.","whatToDo":["Contact Anis about the account’s purchase rules; send a new order only once the purchase is allowed."],"dotnetException":"AuthorizationException"},{"code":"purchase_not_allowed","status":409,"type":"https://developers.anis.ly/errors/order-refused","page":"https://developers.anis.ly/errors/order-refused.md","title":"Order refused","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The purchase conflicts with the current state of the Anis business account, and it was refused. It carries the code `purchase_not_allowed`.","whatToDo":["Place a new order with a new operation id only after the account’s state has changed."],"dotnetException":"AuthorizationException"},{"code":"owner_limit_exceeded","status":409,"type":"https://developers.anis.ly/errors/owner-limit-exceeded","page":"https://developers.anis.ly/errors/owner-limit-exceeded.md","title":"Spending allowance used up","area":"limits","areaTitle":"Limits","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The Anis business account’s spending allowance is used up. This is not a request rate: waiting does not reset it.","whatToDo":["Do not retry in a loop.","Place a new order, with a new operation id, only once you know the allowance has changed."],"dotnetException":"LimitExceededException"},{"code":"daily_limit_exceeded","status":429,"type":"https://developers.anis.ly/errors/daily-limit-exceeded","page":"https://developers.anis.ly/errors/daily-limit-exceeded.md","title":"Daily limit reached","area":"limits","areaTitle":"Limits","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The Anis business account’s daily purchase limit is reached. No reset time is given.","whatToDo":["Do not retry in a loop.","Place a new order, with a new operation id, once you know the limit has cleared."],"dotnetException":"LimitExceededException"},{"code":"rate_limited","status":429,"type":"https://developers.anis.ly/errors/rate-limited","page":"https://developers.anis.ly/errors/rate-limited.md","title":"Rate limited","area":"limits","areaTitle":"Limits","sentToday":true,"sendAgainUnchanged":true,"orderPlaced":"no","meaning":"Too many requests in the current window. The limit is either one Anis staff set on your application or wallet — counting all requests, orders only, or reveals only — or Anis’s own protection. Nothing was recorded against the request. During enrolment it also means the proof has failed five times.","whatToDo":["Wait for the time in `Retry-After` when it is present; otherwise back off exponentially.","Then send again. An order may keep its operation id: a refusal at the door records nothing against it.","During enrolment, after five failed proofs: ask Anis staff to restart the enrolment."],"dotnetException":"RateLimitedException"},{"code":"wallet_disabled","status":409,"type":"https://developers.anis.ly/errors/wallet-disabled","page":"https://developers.anis.ly/errors/wallet-disabled.md","title":"Wallet disabled","area":"access","areaTitle":"Permissions and account","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The wallet is disabled, so it cannot be used right now.","whatToDo":["Contact Anis; send a new request once the wallet is enabled again."],"dotnetException":"AuthorizationException"},{"code":"wallet_expired","status":409,"type":"https://developers.anis.ly/errors/wallet-expired","page":"https://developers.anis.ly/errors/wallet-expired.md","title":"Wallet expired","area":"access","areaTitle":"Permissions and account","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The wallet can no longer be used because the account or its Business subscription has expired.","whatToDo":["Contact Anis to resolve the expiry, then send a new request."],"dotnetException":"AuthorizationException"},{"code":"business_subscription_required","status":409,"type":"https://developers.anis.ly/errors/business-subscription-required","page":"https://developers.anis.ly/errors/business-subscription-required.md","title":"Business subscription required","area":"access","areaTitle":"Permissions and account","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The Anis business account behind your application has no active Business subscription.","whatToDo":["Restore the Business subscription with Anis, then send a new request."],"dotnetException":"AuthorizationException"},{"code":"account_inactive","status":403,"type":"https://developers.anis.ly/errors/account-inactive","page":"https://developers.anis.ly/errors/account-inactive.md","title":"Account inactive","area":"access","areaTitle":"Permissions and account","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The Anis business account behind your application is inactive.","whatToDo":["Contact Anis to confirm or re-enable the account, then send a new request."],"dotnetException":"AuthorizationException"},{"code":"currency_not_supported","status":422,"type":"https://developers.anis.ly/errors/currency-not-supported","page":"https://developers.anis.ly/errors/currency-not-supported.md","title":"Currency not supported","area":"request","areaTitle":"The request itself","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The currency in the request is not the wallet’s currency.","whatToDo":["Send the prices in the currency the catalogue shows for this wallet."],"dotnetException":"ValidationFailedException"},{"code":"card_unavailable","status":409,"type":"https://developers.anis.ly/errors/card-unavailable","page":"https://developers.anis.ly/errors/card-unavailable.md","title":"Card unavailable","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The card cannot be sold to this wallet now — it is no longer offered, or it does not exist.","whatToDo":["Read the catalogue again and choose a card it offers; place a new order with a new operation id."],"dotnetException":"OutOfStockException"},{"code":"quantity_unavailable","status":409,"type":"https://developers.anis.ly/errors/quantity-unavailable","page":"https://developers.anis.ly/errors/quantity-unavailable.md","title":"Quantity unavailable","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The card cannot be sold in this quantity: it is sold out, there is not enough stock, or the quantity is outside the card’s own minimum or maximum.","whatToDo":["Read the catalogue again and place a new order with an available quantity and a new operation id."],"dotnetException":"OutOfStockException"},{"code":"price_changed","status":409,"type":"https://developers.anis.ly/errors/price-changed","page":"https://developers.anis.ly/errors/price-changed.md","title":"Price changed","area":"orders","areaTitle":"Orders","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":"no","meaning":"The price you sent is not the price this wallet pays now. Nothing was charged. The price checked is the card’s `unitPrice` for this wallet — the other prices in the catalogue are for display.","whatToDo":["Read the catalogue again and place a new order at the current `unitPrice`, under a new operation id."],"dotnetException":"PriceChangedException"},{"code":"reveal_not_allowed","status":409,"type":"https://developers.anis.ly/errors/reveal-not-allowed","page":"https://developers.anis.ly/errors/reveal-not-allowed.md","title":"Reveal not allowed","area":"reveals","areaTitle":"Revealing cards","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":null,"meaning":"This card’s codes cannot be shown in its current state.","whatToDo":["Do not retry until you know the card’s state has changed. Contact Anis with the request id if you think it should be revealable."],"dotnetException":"AuthorizationException"},{"code":"invoice_reveal_limit_exceeded","status":409,"type":"https://developers.anis.ly/errors/invoice-reveal-limit-exceeded","page":"https://developers.anis.ly/errors/invoice-reveal-limit-exceeded.md","title":"Invoice too large to reveal","area":"reveals","areaTitle":"Revealing cards","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":null,"meaning":"Revealing a whole invoice is limited to 100 cards, and this invoice has more.","whatToDo":["Reveal the cards you need one by one."],"dotnetException":"AnisApiException"},{"code":"invitation_invalid","status":401,"type":"https://developers.anis.ly/errors/invitation-invalid","page":"https://developers.anis.ly/errors/invitation-invalid.md","title":"Invitation invalid","area":"enrollment","areaTitle":"Enrolling a key","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":null,"meaning":"The invitation or its token is unknown, already used or expired. An invitation is valid for about a day by default.","whatToDo":["Ask Anis staff for a new invitation."],"dotnetException":"EnrollmentRefusedException"},{"code":"challenge_expired","status":409,"type":"https://developers.anis.ly/errors/challenge-expired","page":"https://developers.anis.ly/errors/challenge-expired.md","title":"Challenge replaced","area":"enrollment","areaTitle":"Enrolling a key","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":null,"meaning":"The proof answered a challenge that has been replaced: Anis staff restarted the enrolment, which issues a new invitation and a new challenge. (A proof that is simply too late is not refused — it comes back with `proofState: \"failed\"`.)","whatToDo":["Use the new invitation token Anis staff sent, and enrol again from the key submission.","If your key lives in a vault that needs an approval to sign, arrange that approval before you submit the key: the proof must follow within about 30 minutes."],"dotnetException":"EnrollmentRefusedException"},{"code":"key_proof_invalid","status":422,"type":"https://developers.anis.ly/errors/key-proof-invalid","page":"https://developers.anis.ly/errors/key-proof-invalid.md","title":"Public key invalid","area":"enrollment","areaTitle":"Enrolling a key","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":null,"meaning":"The public key you submitted is not a usable P-256 public key. (A proof of possession that does not verify is not refused — it comes back with `proofState: \"failed\"`.)","whatToDo":["Send only the public half: `kty` `EC`, `crv` `P-256`, and `x` and `y` of exactly 32 bytes each, base64url without padding.","Do not send a private member (`d`)."],"dotnetException":"EnrollmentRefusedException"},{"code":"key_duplicate","status":409,"type":"https://developers.anis.ly/errors/key-duplicate","page":"https://developers.anis.ly/errors/key-duplicate.md","title":"Invitation already used","area":"enrollment","areaTitle":"Enrolling a key","sentToday":true,"sendAgainUnchanged":false,"orderPlaced":null,"meaning":"This invitation has already taken a key — for example, the key submission was sent again after its answer was lost. An invitation takes exactly one key.","whatToDo":["Ask Anis staff to restart the enrolment; it issues a new invitation. A new key pair on the same invitation is refused the same way.","Next time, save the key submission’s answer (it carries the challenge) before anything else."],"dotnetException":"EnrollmentRefusedException"},{"code":"dependency_unavailable","status":503,"type":"https://developers.anis.ly/errors/dependency-unavailable","page":"https://developers.anis.ly/errors/dependency-unavailable.md","title":"Service unavailable","area":"availability","areaTitle":"No decision reached","sentToday":true,"sendAgainUnchanged":true,"orderPlaced":"unknown","meaning":"Anis could not reach a decision because something it depends on was unavailable.","whatToDo":["On an order: the purchase may still complete. Resume with the SAME operation id and the same body after a short wait — never a new id.","On a read: retry after a short wait."],"dotnetException":"DependencyUnavailableException"},{"code":"request_timeout","status":504,"type":"https://developers.anis.ly/errors/request-timeout","page":"https://developers.anis.ly/errors/request-timeout.md","title":"Request timeout","area":"availability","areaTitle":"No decision reached","sentToday":true,"sendAgainUnchanged":true,"orderPlaced":"unknown","meaning":"Anis could not reach a decision in time.","whatToDo":["On an order: the purchase may still complete. Resume with the SAME operation id and the same body — never a new id.","On a read: retry after a short wait."],"dotnetException":"DependencyUnavailableException"},{"code":"internal_error","status":500,"type":"https://developers.anis.ly/errors/internal-error","page":"https://developers.anis.ly/errors/internal-error.md","title":"Internal error","area":"availability","areaTitle":"No decision reached","sentToday":true,"sendAgainUnchanged":true,"orderPlaced":"unknown","meaning":"Something failed inside Anis before a decision was reached. If the answer is marked `Idempotency-Replayed: true`, it is instead the recorded answer of an order that is already closed — nothing was bought.","whatToDo":["On an order: resume with the SAME operation id after a short wait — unless the answer is marked replayed, in which case the order is closed.","On a read: retry after a short wait.","If it persists, contact Anis with the request id."],"dotnetException":"DependencyUnavailableException"}]}