get_purchase_status

Omit purchase for the active/latest one; pass after_revision and the read holds up to `wait_seconds` (contract maximum 45 seconds, `HOLD_MAX_SECONDS`); the server may hold less; follow `next.args.wait_seconds`; call again as soon as it returns.

POST https://api.envoy.money/tools/get_purchase_status

Omit purchase for the active/latest one; pass after_revision and the read holds up to wait_seconds (contract maximum 45 seconds, HOLD_MAX_SECONDS); the server may hold less; follow next.args.wait_seconds; call again as soon as it returns. Without after_revision the reply is immediate. For agent checkout, ready carries the card: pay once and report. No card follows a report or disconnect. After a failed report, follow recovery: start_purchase with retry_of only when offered, or a new ready handout after reconciliation. When checkout_by is envoy, no card is released: Envoy checks out. Relay purchase.question.prompt; submit the user's answer. Stop after four unchanged holds or when told.

TitleServiceRead onlyDestructiveIdempotentExternal sites
Check purchase statussharedtruefalsetruefalse

Send a Central Auth bearer with agent scope. A key-bound connection also sends Envoy-Installation-Proof over this exact request. JSON bodies are limited to 64 KB; a larger body returns HTTP 413 with INVALID_INPUT.

Input

FieldRequiredTypeDescription and rules
purchaseNostringPurchase ID or original idempotency key. minLength 16; maxLength 64; pattern ^(?:pur_[a-f0-9]{32}|(?:[A-Za-oq-z0-9_-]|p[A-Za-tv-z0-9_-]|pu[A-Za-qs-z0-9_-]|pur[A-Za-z0-9-])[A-Za-z0-9_-]*)$
after_revisionNointegerReturn early when the revision changes. minimum 0
wait_secondsNointegerWith after_revision, the read holds up to wait_seconds (contract maximum 45 seconds, HOLD_MAX_SECONDS); the server may hold less; follow next.args.wait_seconds. Without after_revision the read returns at once. minimum 0; maximum 45

Unknown fields are rejected. The exact input schema is on the schemas page.

Synthetic request

{
  "purchase": "synthetic-intent-0001"
}

Hold

With after_revision, a read in a waiting state holds up to wait_seconds (contract maximum 45 seconds, HOLD_MAX_SECONDS); the server may hold less. Never assume a fixed hold length: pass next.args exactly as returned, and stop waiting at next.by. Without after_revision the read returns at once.

Success data

Every reply uses the shared envelope: ok, the purchase, next, user_action and error. Follow next; outputs may gain fields, so ignore ones you do not recognize.

This tool returns its payload in data:

Field in dataRequiredTypeDescription and rules
payment_detailsYesobjectSecret. Release only while ready after authorization (a gift card: after its link was paid); never log or persist these values. card is present exactly when kind is card, voucher exactly when kind is gift_card.
payment_details.kindYes"card" | "gift_card"card: the authorized one-time RuPay card, in card. gift_card: the paid gift card, in voucher.
payment_details.cardNoobject—
payment_details.checkout_codeNostringOptional checkout code, this card's bank OTP: when the bank page asks for a code or OTP, enter the checkout code there once, immediately. Repeated reads do not fund another card. When checkout_code_expires_at is present, read status again once the code expires.
payment_details.checkout_code_expires_atNostringWhen this checkout code expires. Present only with a code whose validity is known. It is not when spending access closes, and not the expiry printed on the card. format date-time
payment_details.amount_limitYesobject—
payment_details.checkout_attempt_idNostringThe checkout attempt carried by this handout. Include this exact value in report_checkout_result; never substitute an attempt from a later read. pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
payment_details.expires_atNostringWhen spending access closes. Omitted when unknown; it is not the checkout code expiry or the expiry printed on the card. format date-time
payment_details.voucherNoobjectPresent exactly when kind is gift_card. value equals purchase.amount.

Secret paths: data.payment_details. They carry one-time card details while the purchase is ready; never log, store or show them. Examples use synthetic values only.

Synthetic result

Example synthetic-completed-receipt (synthetic data):

{
  "ok": true,
  "contract": "envoy@2026-10",
  "tool": "get_purchase_status",
  "request_id": "req_synthetic",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "server_time": "2026-09-29T12:00:00Z",
  "replayed": false,
  "purchase": {
    "purchase_id": "pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c",
    "service": "purchase",
    "idempotency_key": "synthetic-intent-0001",
    "revision": 4,
    "terminal": true,
    "state": "completed",
    "user_task": null,
    "reason_code": null,
    "status_text": "This purchase is complete.",
    "rail": "otu_card",
    "rail_reason": "RAIL_OTU_PREFERRED",
    "checkout_by": "agent",
    "merchant": {
      "name": "Example Store",
      "url": "https://shop.example.test"
    },
    "amount": {
      "minor": 249900,
      "currency": "INR",
      "display": "₹2,499.00"
    },
    "description": "Headphones",
    "details": {
      "complete": true,
      "missing": []
    },
    "question": null,
    "follow_up": {
      "id": "feedback-pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c",
      "kind": "feedback",
      "prompt": "How did this purchase go? The user can rate it from 1 to 5 and add a few words."
    },
    "approval": {
      "state": "approved",
      "method": "passkey",
      "decide_by": "2026-09-29T12:15:00Z",
      "approval_url": null
    },
    "payment_ready": {
      "available": false,
      "kind": "card",
      "expires_at": null
    },
    "money": {
      "status": "debited",
      "paid": {
        "minor": 249900,
        "currency": "INR",
        "display": "₹2,499.00"
      },
      "merchant_order_ref": "SYNTHETIC-ORDER-0001"
    },
    "receipt": {
      "merchant_order_ref": "SYNTHETIC-ORDER-0001",
      "paid": {
        "minor": 249900,
        "currency": "INR",
        "display": "₹2,499.00"
      },
      "card": null,
      "completed_at": "2026-09-29T12:20:00Z"
    },
    "chain": {
      "supersedes": null,
      "superseded_by": null
    },
    "agent": {
      "agent_id": "origin:https://host.example.test",
      "display_name": "Synthetic Host",
      "verification": "origin"
    },
    "created_at": "2026-09-29T12:00:00Z",
    "updated_at": "2026-09-29T12:20:00Z"
  },
  "data": null,
  "next": {
    "action": "done",
    "tool": null,
    "args": null,
    "instruction": "The purchase is complete. Tell the user, including the order reference from purchase.receipt.merchant_order_ref when it is present, then carry on with the user's task.",
    "after_seconds": null,
    "by": null
  },
  "user_action": null,
  "follow_ups": [
    {
      "tool": "submit_answer",
      "args": {
        "purchase": "pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c",
        "question": "feedback-pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c",
        "type": "feedback"
      },
      "why": "Optional feedback about this completed purchase."
    }
  ],
  "error": null
}

Errors

A failure has ok: false, changes nothing, and carries error plus one next. Branch on error.code and next, not on the HTTP status. The contract declares every code below for every tool; which one a call returns depends on the request and the purchase state.

CodeHTTP statusMeaningWhat the agent does
INVALID_INPUT400Fix the supplied input.Fix every field listed in error.fields, then call the same tool once more.
UNAUTHENTICATED401Reconnect through Central Auth.Ask the user to reconnect Envoy, then retry this call.
NOT_ALLOWED403The operation is not allowed.This connection may not do that. Tell the user; do not retry.
SERVICE_NOT_ENABLED403The service is not enabled.This Envoy service is not enabled for the user. Tell the user; do not retry.
NOT_FOUND404Purchase absent or owned by another user.No purchase matches that reference. Check the purchase id from this task; do not start a new purchase to recover.
IDEMPOTENCY_CONFLICT409The same key has different input.Retry with the original inputs unchanged, or use a new idempotency_key only for a genuinely new purchase.
ACTIVE_PURCHASE_EXISTS409An active purchase already exists.Another purchase is in progress. Show the user the user_action message and stop this attempt.
STATE_CONFLICT409The operation conflicts with the current state.This conflicts with the current state. Tell the user; do not retry.
NO_RAIL422No rail can serve this purchase; nothing was created.Envoy cannot pay this purchase. Tell the user why using error.message; do not retry or split it.
RATE_LIMITED429Wait before retrying.Wait next.after_seconds, then retry the same call unchanged.
UNAVAILABLE503The service is unavailable; follow retryable and next.Wait next.after_seconds, then retry the same call unchanged; never pay elsewhere meanwhile.
CLIENT_UPDATE_REQUIRED426Update the client.This client is too old. Tell the user to update it.

Downloads

OpenAPI · MCP catalog · Synthetic examples · Schemas

On this page