{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-apis/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"Idempotency","projectTitle":"Vilna Docs","description":"Retry mutations with Idempotency-Key: operation scope, replay windows and recovery for the Platform, Management and VKS APIs.","siteUrl":"https://docs.vilna.io","lang":"en-US","image":"https://cdn.vilna.io/docs/og/26103121/en/apis-idempotency.png","meta":[{"name":"og:type","content":"website"},{"name":"og:site_name","content":"Vilna Documentation"},{"name":"og:image:width","content":"1200"},{"name":"og:image:height","content":"630"},{"name":"twitter:card","content":"summary_large_image"},{"name":"robots","content":"max-image-preview:large"}],"llmstxt":{"title":"Vilna API Documentation","description":"Vilna Platform API monitors public blockchain activity, balances and invoices and delivers signed webhooks. It does not sign or broadcast transactions. VKS separately coordinates account setup, signer approvals and signing, retains signed results and can submit a complete transaction to a node. Node acceptance is not blockchain confirmation. Each API uses its own scoped credential in X-Api-Key. Workspace setup and VKS-key issuance start in the Dashboard.\n","details":{"content":"**Platform monitoring.** Platform observes merchant-controlled addresses,\nsupplied directly or derived from the merchant's extended public key (xPub).\nInvoices report incoming on-chain activity; they do not initiate transfers.\n\n**APIs and their credentials.**\n\n- Platform API (api.vilna.io) - monitor addresses and extended public keys, read\n  balances and transactions, reconcile incoming payments, create invoices, and\n  receive events.\n- Blockchain RPC (rpc.vilna.io) - JSON-RPC and gRPC node access across every\n  supported network behind one key.\n- Management API (mgmt.vilna.io) - published workspace, project, member and key\n  operations, with Dashboard bootstrap and credential grant limits.\n- VKS API (vks.vilna.io) - workspace signers, vaults, accounts, signing requests,\n  signed results and optional asynchronous send. Uses a Dashboard-issued VKS key\n  with vks:access; the public Management API has no VKS-key issuance route.\n\n**Pages with no markdown source**, so they cannot be linked below:\n\n- Product overview: https://docs.vilna.io/\n- All guides: https://docs.vilna.io/guides\n"},"excludeFiles":["legal/terms.md","legal/privacy.md","legal/cookies.md","@l10n/ru/legal/terms.md","@l10n/ru/legal/privacy.md","@l10n/ru/legal/cookies.md"],"sections":[{"title":"Getting Started","description":"What the platform is, how to make a first call, and answers to common questions","includeFiles":["get-started/quickstart.md","get-started/dashboard.md","get-started/core-concepts.md","get-started/members.md","get-started/faq.md"]},{"title":"API Reference","description":"Authentication, permissions, idempotency, errors, standards, and per-service endpoint documentation","includeFiles":["apis/authentication.md","apis/permissions.md","apis/idempotency.md","apis/errors.md","apis/standards.md","apis/networks.md","apis/platform/@v2/index.md","apis/platform/@v2/webhooks.md","apis/platform/@v2/api.yaml","apis/mgmt/index.md","apis/mgmt/api.yaml","apis/vks/index.md","apis/vks/api.yaml","apis/rpc/index.md","apis/rpc/json-rpc.md","apis/rpc/grpc.md"]},{"title":"Developer Guides","description":"Integration patterns, events, notifications, and tooling","includeFiles":["guides/events.md","guides/channels.md","guides/tokens.md","guides/integration-patterns.md","guides/mcp.md","guides/simulation.md","guides/invoices.md","guides/vks.md"]},{"title":"Trust and custody","description":"The non-custodial model in plain terms","includeFiles":["legal/non-custodial.md"]},{"title":"Optional","description":"Background reading and release history","includeFiles":["get-started/blockchain-basics.md","changelog.md"]}]},"jsonLd":{"@context":"https://schema.org","@graph":[{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://docs.vilna.io/"},{"@type":"ListItem","position":2,"name":"API Reference","item":"https://docs.vilna.io/apis"},{"@type":"ListItem","position":3,"name":"Idempotency"}]},{"@type":"TechArticle","headline":"Idempotency","description":"Retry mutations with Idempotency-Key: operation scope, replay windows and recovery for the Platform, Management and VKS APIs.","url":"https://docs.vilna.io/apis/idempotency","datePublished":"2026-10-26","dateModified":"2026-10-31","image":"https://cdn.vilna.io/docs/og/26103121/en/apis-idempotency.png","author":{"@id":"https://vilna.io/#organization"},"publisher":{"@id":"https://vilna.io/#organization"}}]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"idempotency","__idx":0},"children":["Idempotency"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use one ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Idempotency-Key"]}," for one mutation intent. If a response is lost, retry that intent with the same key and request inputs. A completed intent can return its saved response without repeating the HTTP operation's effect."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"scope","level":2,"__idx":1},"children":["Where the header applies "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The operation reference declares whether the header is required. HTTP POST alone does not determine the policy."]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"API"},"children":["API"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Required operations"},"children":["Required operations"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Exceptions"},"children":["Exceptions"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/platform/api"},"children":["Platform v2"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Declared state changes and external actions, including balance refresh, channel tests and notification resends"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["GET, balance search and EVM simulation"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/mgmt/api"},"children":["Management"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Every POST, PATCH and DELETE on this surface"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["GET; dashboard-session operations are outside this API-key surface"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/vks/api"},"children":["VKS"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Every POST and DELETE, including signer invitations, abort actions and transaction send requests"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["GET"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["These rules do not extend to blockchain JSON-RPC or gRPC calls. HTTP effect deduplication does not guarantee exactly-once webhook delivery, signing or blockchain execution. A VKS send ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["202"]}," records the request; follow transaction logs for its outcome, and check chain confirmation separately."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"header","level":2,"__idx":2},"children":["Header and intent identity "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Send exactly one ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Idempotency-Key"]}," header occurrence with ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["1 to 128 visible ASCII bytes"]}," (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["0x21"]}," through ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["0x7e"]},", pattern ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["^[!-~]+$"]},"). Values are opaque and case-sensitive. A UUID is allowed but not required. Do not trim, lowercase or split the value: a comma is literal data. Repeated headers are invalid even if their values match; whitespace and non-ASCII characters are invalid."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A binding identifies the caller, operation and target. Platform also scopes it to the project; VKS scopes it to the workspace. Management targets identify the relevant workspace or resource. The same text used by another caller or against another target is not a recovery mechanism. Keep the original caller and scope when retrying."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before the first attempt, save the key, method, target, request parameters and complete body with your business intent. Preserve them across process restarts. Generate timestamps, expiry values and random body fields once; a retry must not refresh an invoice's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["expires_at"]},". Each distinct intent gets a different key. Do not reuse a completed key for a later action, even after its response expires."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every attempt checks current ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/authentication"},"children":["authentication"]}," and ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/permissions"},"children":["permissions"]},", including replay. The key grants no access. Revoked credentials or removed permissions can prevent replay; switching to another caller can produce a separate effect."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"example","level":2,"__idx":3},"children":["Request and retry "]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Open ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/platform/api/address/create-external-address"},"children":["Register an external address"]},". Use a project key with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["api:address:write"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Choose your address, chain family and label. Generate one ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Idempotency-Key"]}," and save it with the complete request body in your durable intent record."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Send the request using the operation page's request builder or one of its client examples."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If the response is lost, retry with the same key, body, parameters and credentials. Do not generate a new key while the outcome is unknown."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Save the returned resource identity. For another address or label, resolve the original intent before starting a new one."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"replay","level":2,"__idx":4},"children":["Replay windows and current state "]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Result"},"children":["Result"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Replay window and conditions"},"children":["Replay window and conditions"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Ordinary successful response"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["24 hours from original successful completion"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Platform response containing a webhook signing secret"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["60 seconds from completion, only while that secret is current; replacement, deletion or revocation can make replay unavailable"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["API/RPC key secret created through the Management API"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["60 seconds from successful creation, with current access and permitted key state; revoked or deleted keys are not restored"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["VKS ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /signers"]}," invitation secret"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["60 seconds from successful creation, only while the invitation is unused, unexpired and not deleted"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Retries never extend these windows. Save secrets immediately in a secrets manager; later GET requests do not recover their plaintext."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The VKS invitation's replay window is distinct from its first-use deadline and from registration retry by the same signer using its previously received token. An invitation can remain usable after its HTTP response can no longer be replayed. After successful registration, the same signer can retry setup with its original token even after the first-use deadline, until the signer is deleted."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A replay returns the original response snapshot, including its original resource state. Use the resource's GET operation for current state ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["when you know its ID"]},". VKS abort/deletion and Management project-deletion replays can return their original success after changing or removing the target, while current workspace access still permits replay. A removed workspace does not remain accessible through its old key."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A durably bound key stays bound permanently after response expiry. Expiry does not run the operation again or permit another effect with that binding. Header rejection or validation before an effect does not by itself establish a durable binding; not every attempted key is reserved, and not every error response is cached."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"id":"recovery","level":2,"__idx":5},"children":["Responses and recovery "]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Read the problem ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["code"]}," as well as the HTTP status. Other business conflicts can also return ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["409"]},"; see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/apis/errors"},"children":["Errors"]},"."]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Response"},"children":["Response"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"What to do"},"children":["What to do"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Missing, malformed or repeated header: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["400"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Fix the header. Platform and VKS use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["idempotency_key_invalid"]},"; Management documents the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["InvalidRequestProblem"]}," response schema. A rejected header does not establish a saved effect."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["409 idempotency_in_progress"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Another attempt with this binding is running. Back off and retry the same key and inputs; do not launch parallel replacements."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["409 idempotency_request_mismatch"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Compare against the saved original method, target, parameters and body. Restore the original inputs for a retry; changed inputs must not overwrite this intent."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["409 idempotency_result_expired"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The saved response is no longer available. Reconcile the old outcome; the operation is not repeated. VKS also uses this code when a signer invitation is no longer eligible for secret replay."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["409 idempotency_result_unavailable"]}," (Platform)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check current resource/secret state. Replay cannot restore a replaced or removed secret."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Current ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["401"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["403"]}," or scope/resource ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["404"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Restore legitimate access where possible. The intent key bypasses no access check."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Timeout, connection loss or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["5xx"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The effect may already have occurred. Use backoff with the same key and unchanged inputs while replay is available."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Explicit validation failure before any effect"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Correct the invalid input according to the operation. This differs from a lost response with an unknown outcome; do not assume all failures have a replayable result."]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"Do not replace an uncertain intent"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Never automatically generate a fresh key after an expired, unavailable or uncertain response. A new key can create a second effect. A deliberate replacement is a new business action after reconciling the original outcome."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you know the resource ID, read it and its relevant logs. If a creation response was lost and you do not know the ID, use only list/filter operations actually provided by that API and your saved business correlation data to identify the result. There is no public idempotency-status or lookup-by-key endpoint. Listing may not identify the resource uniquely, and metadata is not a universal lookup filter. If the outcome remains unresolved, retain the original intent and request evidence for support; do not assume that a lost resource ID can always be recovered."]}]},"headings":[{"value":"Idempotency","id":"idempotency","depth":1},{"value":"Where the header applies","id":"scope","depth":2},{"value":"Header and intent identity","id":"header","depth":2},{"value":"Request and retry","id":"example","depth":2},{"value":"Replay windows and current state","id":"replay","depth":2},{"value":"Responses and recovery","id":"recovery","depth":2}],"frontmatter":{"seo":{"title":"Idempotency","description":"Retry mutations with Idempotency-Key: operation scope, replay windows and recovery for the Platform, Management and VKS APIs.","image":"https://cdn.vilna.io/docs/og/26103121/en/apis-idempotency.png","jsonLd":{"@context":"https://schema.org","@graph":[{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://docs.vilna.io/"},{"@type":"ListItem","position":2,"name":"API Reference","item":"https://docs.vilna.io/apis"},{"@type":"ListItem","position":3,"name":"Idempotency"}]},{"@type":"TechArticle","headline":"Idempotency","description":"Retry mutations with Idempotency-Key: operation scope, replay windows and recovery for the Platform, Management and VKS APIs.","url":"https://docs.vilna.io/apis/idempotency","datePublished":"2026-10-26","dateModified":"2026-10-31","image":"https://cdn.vilna.io/docs/og/26103121/en/apis-idempotency.png","author":{"@id":"https://vilna.io/#organization"},"publisher":{"@id":"https://vilna.io/#organization"}}]}}},"lastModified":"2026-10-31T22:07:16.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/apis/idempotency","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}