Replies and next steps
Read an MCP tool result: the briefing first, then What to do, then the data keys for the next call.
An MCP tool result is a plain-English briefing for the user and the agent, followed by one line of JSON with only what the next call needs. Read the briefing, do what What to do says, and use the JSON line for the next call.
Support revision: envoy@2026-10. Last updated: 3 November 2026.
The HTTP API (/tools/*) returns the full reply envelope instead. See the HTTP API for that format. This page covers MCP only.
What an MCP tool result contains
contentholds one text item: the briefing, a blank line, then the data as one JSON line.structuredContentis the same JSON object. The MCPoutputSchemadeclares it.isErroristruewhen the call returned an error. A checkout report may already be saved when its reply fails._meta["money.envoy/support"]holds diagnostics for support and hosts. Hosts do not pass it to the model.
The briefing has one to three sentences for the user, then What to do: for the agent. It has no codes, ids, field paths or timestamps.
Sometimes the user must act in the Envoy app and the agent has a call to make. Then What to do: comes first. Tell the user the app step, then follow the returned next.tool and next.args to check progress. The user part says the assistant carries on by itself, and asks the user to reply "done" only if it doesn't.
A synthetic waiting reply:
What to do: Tell the user the message below once; they can't see tool results. They need to do it within about 15 minutes. Call get_purchase_status with the next tool and args from the data below: it waits up to 45 seconds for a change. Follow each returned next action until the situation changes or Envoy says to stop. get_purchase_status moves on by itself as soon as the user finishes in the Envoy app; the user doesn't need to tell you.
Approve this purchase in the Envoy app. (₹2,499.00 at "Example Store") Your assistant carries on by itself once you approve.
{"situation":"waiting_for_user","money":"not_charged","purchase_id":"pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c","next":{"tool":"get_purchase_status","args":{"purchase":"pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c","after_revision":1,"wait_seconds":45}}}The full synthetic replies for every tool are in the MCP reference.
A held get_purchase_status call that sends a progressToken is answered as a stream; see Transport.
Read a result
- Tell the user the first part of the briefing in your own words.
- Do what
What to dosays. - Wait
next.wait_secondswhen present, then passnext.argsunchanged tonext.tool. This delay precedes the call;next.args.wait_secondsbounds waiting inside it. - Use
purchase_idfor later calls. - Never show the JSON line, or any code, id, key or timestamp, to the user. The user cannot use them.
- Give
support_refonly if the user asks for help.
Data keys
| Key | Values | When |
|---|---|---|
situation | See the table below. | Purchase results. |
money | not_charged, set_aside, charged, refunding, refunded, unknown | Purchase results. |
purchase_id | The purchase reference. | Purchase results. Use it for later calls. |
checkout_by | agent or envoy | Purchase results, once Envoy decides. agent: use the authorized card or paid gift-card voucher once. envoy: Envoy checks out; no card is released, and you never open the merchant payment step. Act on the latest reply. |
next | {tool, args, wait_seconds} | When the agent should call something. |
purchase | Open question, or gift-card funding with url, payable amount and expires_at. | Questions appear while an answer is needed. Funding appears only for a gift-card payment-link task. Give the user purchase.funding.url to open and pay themselves; the briefing text carries the same link. It is never an approval link, and app tasks have no link. |
spending_closed | Boolean, when supplied. | Spending access is closed when true. It does not prove issuer blocking or a refund. |
follow_up | {tool, args} for submit_answer. | Optional feedback on done, or an optional vault save on a ready card. Follow the supplied args; vault saving can hold the card while it runs. |
retry | same_call, after_fix, check_status_first, new_purchase, no | Errors and stopped purchases. |
fix | [{field, problem}] | Input errors. |
card | Payment details with kind card or gift_card. | Only on an authorized ready get_purchase_status. kind: card carries the one-time card; kind: gift_card carries voucher. Both are secret. Preserve checkout_attempt_id when supplied for the report. |
support_ref | EV-XXXXXX | Stopped, confirming and support situations, and errors. |
account, transactions, next_cursor | The data read. | get_account and list_transactions. |
merchants | Gift-card merchants: name, domain, amounts, amount_range, discount_percent and redeem_at. Use the returned denominations or range; the discount is a maximum advertised saving, not the captured charge. redeem_at is account, checkout or null when unknown. | list_gift_card_merchants (deprecated name get_merchants). |
products | Elixir marketplace products: product_id, name, brand, image, price (for one), quantity, total, valid_until and merchant_url. Show the name and price; never show product_id. Empty when Elixir has nothing to offer. | search_products. |
Over MCP the agent does not see ok, purchase.state, status_text, next.action, error codes, reason codes or the rail. Those are REST only; see Errors and reason codes.
What each situation means
situation says where the purchase stands. money says whether money moved. Read both. The same situation can come with different money values, and the money value changes what you tell the user.
| Situation | money | The agent does | The agent tells the user |
|---|---|---|---|
needs_details | not_charged | Show the user Envoy's question word for word and wait. Call submit_answer with next.args and the user's words as answer. | Which detail Envoy needs before the purchase can continue. |
needs_answer | Read the returned value. | Show the user Envoy's question word for word and wait. Call submit_answer with next.args and exactly what the user said as answer. Never answer for the user. An otp question asks for a merchant or Instinct vault sign-in code, as the exact prompt states: send it once, then never repeat or keep it. A bank or payment OTP never belongs here. Envoy never asks for a password. | Envoy's question, word for word. |
waiting_for_user | not_charged | Show the returned user task once. For a gift-card payment link, give the link and its payable amount to the user; never open or pay it yourself. Follow next to check progress. Wait next.wait_seconds when present, then call get_purchase_status. Stop when next has no tool; then ask the user to reply "done". | The returned app task, or the gift-card payment link and price. The user completes it themselves. |
working | not_charged or set_aside | Call get_purchase_status again as next says. Start no other payment. When checkout_by is envoy, do not open the merchant checkout or pay. | Envoy is preparing the purchase, or placing the order itself when checkout_by is envoy. |
ready | set_aside | Only when checkout_by is agent. Check card.kind. Use the one-time card or redeem the paid voucher once at this merchant as instructed. Then call report_checkout_result. Never show card to the user. | The card or gift card is ready. Merchant payment is not yet confirmed. |
confirming | unknown, set_aside or refunding | Do not pay again or start a new purchase. Follow next. If next has no tool, stop checking for now. For a one-time-card retry, pay again only when the returned instruction explicitly permits it and status returns a new ready handout. | The purchase is not confirmed yet. The Envoy app shows the result. Give support_ref if they ask for help. |
done | charged or not_charged | Carry on with the task. | The purchase is complete. Follow the briefing: the merchant may collect payment on delivery. Give its order reference when supplied. |
stopped | not_charged | Stop this purchase. Do not retry it. Start a new purchase only when retry is new_purchase and the user still wants it. | The purchase ended and the user was not charged. |
stopped | refunded | Same as above. | The purchase ended and the money was returned. |
needs_support | set_aside, refunding, unknown, or any value when Envoy cannot read the purchase's answer | Do not pay again or start a new purchase for this item. | Envoy cannot confirm what happened. The Envoy app will show the result. Give support_ref if they ask for help. |
stopped always has money of not_charged or refunded. Suppose a purchase ended and money is set_aside, refunding or unknown. Then Envoy reports needs_support instead. The money outcome is not safe to call.
A synthetic confirming reply:
Envoy is confirming whether the payment for ₹2,499.00 at "Example Store" went through.
What to do: Tell the user it isn't confirmed yet. Don't pay again or start a new purchase for this. Call get_purchase_status again to follow it: it waits up to 45 seconds for a change. If the user asks for help, give them the reference EV-72Z0SF.
{"situation":"confirming","money":"unknown","purchase_id":"pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c","next":{"tool":"get_purchase_status","args":{"purchase":"pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c","after_revision":1,"wait_seconds":45}},"support_ref":"EV-72Z0SF"}A synthetic stopped reply:
This purchase could not be completed. You have not been charged. (₹2,499.00 at "Example Store")
What to do: Tell the user in your own words and stop this purchase; don't retry it. If they still want it, you can start a new purchase. If the user asks for help, give them the reference EV-72Z0SF.
{"situation":"stopped","money":"not_charged","purchase_id":"pur_5b1e9c7a3f2d5a8e9c0b1d2e3f4a5b6c","retry":"new_purchase","support_ref":"EV-72Z0SF"}Map MCP situations to HTTP states
Purchase states over HTTP and MCP
waiting_for_userMCPwaiting_for_userThe user completes the app task or pays the returned gift-card link.processingMCPworkingEnvoy prepares payment, obtains a gift-card quote or checks out.readyMCPreadyAgent route only. Pay once, then report.verifyingMCPconfirmingMoney is unsettled. Never pay again.completedMCPdoneThe purchase is complete. Read money separately, including payment collected on delivery.
needs_answer, needs_detailsEnvoy needs something only the user can give. Show the prompt word for word.failed, cancelledMCP stopped when money is not_charged or refunded; otherwise needs_support.supersededMCP working. A linked purchase replaced this one and needs its own approval.HTTP purchase.state | MCP situation |
|---|---|
needs_details | needs_details |
needs_answer | needs_answer |
waiting_for_user | waiting_for_user |
processing, superseded | working |
ready | ready |
verifying | confirming, or needs_support |
completed | done |
failed, cancelled | stopped when money is not_charged or refunded, otherwise needs_support |
Never copy an MCP parser into HTTP code, or the reverse.
Read money
money says whether money moved: not_charged (nothing moved), set_aside (reserved for this purchase), charged, refunding, refunded or unknown. When money is unknown, treat the purchase as confirming. Never pay again to get unstuck, because the first payment may have gone through.
Read retry
retry appears on errors and on stopped or unsupported purchases. It says whether the same call is safe to send again.
| Value | Appears when | The agent does |
|---|---|---|
same_call | A rate limit, or a retryable outage. | Wait next.wait_seconds, then repeat the same call unchanged. Pay no other way meanwhile. |
after_fix | An input was rejected. fix lists each field. | Fix every field in fix. Call the same tool once more. |
check_status_first | An outage after a write. Envoy may already hold the request. | Call get_purchase_status before anything else. The write may have happened. |
new_purchase | A purchase ended with nothing charged, and a new one could work. | Do not retry this purchase. Start a new one only if the user still wants it. |
no | A refusal, a limit, an unknown outcome or an outage with no retry. | Do not retry. Tell the user. |
After a lost reply or a timeout, call get_purchase_status first. See Recover a purchase.
Escalate to support
When a reply carries support_ref (for example EV-72Z0SF), give it to the user if they ask for help. The user quotes it to support at envoy.money/support. Support finds the request, its error and its state with that one reference. The agent never sees those codes.
support_ref appears on confirming, needs_support, most stopped results and most errors. It does not appear on input errors, NOT_FOUND-style lookups, key conflicts or rate limits, because the agent fixes those itself. There is no status page. See Resolve a connection or purchase problem.
Rate limits
Each access token may make 120 tool requests per minute, shared between MCP and HTTP. Over that, a tools/call returns a tool result with isError: true, a wait time in next.wait_seconds and retry same_call. Wait that long, add a little random jitter, and repeat the same call. Other over-limit MCP requests get JSON-RPC error -32000. Requests that fail authentication are also limited per client IP.
Protect the card details
card contains secret payment details: either a one-time card or a gift-card voucher. It appears only in an authorized ready get_purchase_status, in both the JSON line and structuredContent. The briefing never carries card values. A report stops use of the current handout. Envoy can return a new ready handout after reconciliation. A disconnect ends disclosure. A cancelled purchase does not release credentials. Host history may keep the text.
- Use the card once, at the checkout for this purchase. Then call
report_checkout_result. Reportpaidonly if the merchant confirmed the payment. If you cannot tell whether payment completed, reportfailedwithfailure_reason: other. - If the checkout fails, report
failedwith the closestfailure_reason. Follow the returned recovery option. An eligibleretry_ofcan use Envoy checkout;price_changedandout_of_stockdo not offer that retry. See Report the result. - Keep card details, checkout codes, voucher codes and PINs out of replies, files, logs, traces, memory, feedback and analytics.
- Clear local copies after use.
Support reference and _meta
support_ref (for example EV-72Z0SF) is the one short reference for a result. Support finds the request with it. Give it to the user only when the user asks for help.
_meta["money.envoy/support"] carries support_ref, request_ref, request_id, trace_id, tool, error_code, reason_code, state, user_task, situation, rail and rail_reason. It is for hosts and support, not for the model. Do not show it to the user.
Read the envelope
REST only. An MCP agent does not see this envelope. The values below are what POST /tools/:tool returns.
The HTTP API returns one envelope for every tool, on success and on failure. Read ok, then follow next.
| Field | What it tells you |
|---|---|
ok | true means the call worked. false usually means the call changed nothing; when next reads a purchase, read it first. |
purchase | The purchase snapshot, or null: state, status_text, money. |
data | The tool's payload, or null. While ready, get_purchase_status holds payment_details. |
next | What the agent does now: action, tool, args, after_seconds, by. |
user_action | The user task and safe message. url is null except for a gift-card payment link that the user opens and pays. |
error | Set when ok is false: code, message, fields, reason_code, retryable, retry_after_seconds. |
replayed | true when the call returned an existing purchase, such as a start_purchase retried with the same key. |
request_id, trace_id, contract | For support and debugging. Do not branch on them. |
The REST-only next.action values are call_tool, checkout, fix_input, retry, continue, done, stop, reconnect and update_client. Every field is in the shared schemas, and every error code is in Errors and reason codes.
Which tools change things
get_account, list_transactions, list_purchases, list_gift_card_merchants, get_merchants, search_products and report_checkout_step do not move money. A checkout-step reply returns no card; keep using the authorized handout rather than reading ready status again. get_purchase_status reads progress, but a ready read releases authorized payment details and can start Envoy's gift-card checkout. Do not poll or auto-refresh ready status. start_purchase, report_checkout_result and cancel_purchase can change a purchase or money; retry each only as the result directs, with the same key or purchase reference. answer_purchase_question (deprecated name submit_answer) sends the user's reply to an open question, or optional feedback; retry it with the same key and the same answer. Tool annotations describe these effects; they do not grant permission.