Skip to content
Integra Agentic Terms

Declines

Every decline code the gate returns, what it means, what was and was not done, and the detail codes it carries.

The gate never throws for a protocol outcome. Every function returns its result or a decline:

import type {  } from "@integraledger/lcp";
import type {  } from "@integraledger/terms";

type  = {
  readonly : { readonly : ; readonly : string };
  readonly ?: { readonly : unknown; readonly : ; readonly :  };
};

In Python, a decline is Declined(code, detail, moved), with moved a Moved(signed, atr_bytes, h) or None.

code is one of the twelve values below. detail is either a sentence for a person to read, or a refusal code, normally of the form <protocol>/<reason>, such as x402/no-payable-option or mpp/credential-malformed (member-failed, for a binding member that threw in openChannel or within, has no prefix). Program against code; log detail.

Decline codes

CodeReturned whenSigner called?
pairing-not-supportedThe binding names no pairing the gate serves. chosen, or a channel hold, belongs to another pairing. The pairing has no channel (for openChannel and within). An MPP in-session action the binding does not build (mpp/within-action-not-built).No
offer-unreadableThe binding cannot read the seller's document, the chosen payment carries no choice, or a build refuses. The payment request of an approved agreement payment is one the protocol package's read refuses for a fault of its own (its version, legal context or agreement URL, or an accepts that is not a list of at most 32 entries holding an option), or its option is not one of that request's accepts (x402/option-not-in-document). For recordCharge: the charged amount is not a decimal, is below the charge already recorded, or is above the largest amount signed.No
no-payable-optionNo option in the document is payable by the signer's account on its network; no option of the agreement URL's payment request is payable by the signer with a pairing whose payment is a public proof (an option whose maxTimeoutSeconds is not a JSON number with an integral value from 1 to 253 − 1 included is payable by none); an input the build needs is missing or malformed (<protocol>/input-missing); the options of transact or agree hold something other than their members, or a member of the wrong kind, or the inputs given to confirm, agree or within are not an object, or the account of the signer or agreement signer given to transact or agree is not a string, or a Solana refund value, or a Solana refund's paymentResponse or its errorReason, is given in another form (<protocol>/input-malformed); or a later channel challenge asks for a payment in a channel the hold did not open.No
link-not-httpsThe ATR's link, or the agreement URL, is not an https URL. detail is <protocol>/link-not-https for another scheme and <protocol>/legal-context-malformed for a value that is not a URL. Nothing was fetched.No
atr-unfetchableThe link answered a status other than 200, redirected, answered 200 with a Content-Encoding other than identity, did not answer within 10 seconds, or failed.No
atr-too-largeThe ATR is larger than 1,048,576 bytes, by its declared Content-Length or as it streamed. Also for bytes over that size passed to finish, check or openChannel.No
hash-mismatchSHA-256 of the served bytes is not the advertised H. The agreement URL's challenge advertises another H. A later channel challenge advertises another H than the held one, or the held bytes do not hash to the held H.No
signer-failedYour signer threw (TypeScript) or raised (Python).Yes
signed-not-boundThe pairing does not read the hash of the compared bytes from the payment, from a payment presented to check or from a channel opening; the signer's answer did not complete the payment; a channel opening or voucher does not belong to the held channel; the signed agreement payment or channel opening is not plain JSON (nested past 64 levels, or not written by JSON). The payment is not returned, and an agreement payment is not sent.Yes, or not needed
agreement-not-offeredThe pairing's payment is not itself a public proof of H, and the seller's offer names no agreement URL.No
agreement-pendingThe agreement URL answered 202 before the gate paid (another agreement payment for this ATR is settling); the agreement payment is sent and not recorded within the paid option's maxTimeoutSeconds plus 180 seconds; or the caller's signal ended the exchange after the agreement payment is sent.No, for a 202 before paying; otherwise for the agreement only
agreement-failedThe unpaid request: the agreement URL could not be reached, or answered a status other than 200, 202 or 402, or a 402 without a readable PAYMENT-REQUIRED. The paid request: any answer but 200, 202 or a 5xx, a 402 included (an unreachable URL, a timeout and a 5xx are retried). Either request: a redirect; a 200 or 402 with a Content-Encoding other than identity; or a 200 that is not a receipt for this H, a receipt over 64 KiB included. The approved agreement payment names another agreement URL. The caller's signal ended the exchange before the agreement payment is sent.For the agreement only, when it failed after payment

The MCP server adds three codes of its own:

CodeReturned whenSigner called?
hold-unverifiedA channel hold passed to atr_channel_record_charge or atr_channel_within is not one this server process returned, unchanged: its mac does not verify. See channel holds.No
opening-unverifiedA channel opening passed to atr_channel_open is not one this server process returned, unchanged: the mac beside it does not verify. See channel holds.No
chosen-unverifiedThe chosen passed to atr_agree, or to atr_finish for a pairing with a channel, is not one atr_confirm returned in this server process, unchanged: its mac does not verify. Nothing is fetched. See atr_agree and channel holds.No

moved

Some signers move the payment themselves: a Lightning node pays the invoice, a signer broadcasts a transaction it was asked to broadcast, a session opening is sent on chain. If the gate declines after that, the decline carries moved:

  • signed: the payment as signed, in the protocol's own form (or the signer's answers, in order, for a payment signed in steps);
  • bytes (atr_bytes in Python): the ATR's bytes;
  • h: their SHA-256.

The agreement exchange does the same: once the agreement payment has been sent, every decline carries it as moved.

Keep moved. It is a payment that has left, or may have left, your wallet. For the payment for the resource, present it again to the seller rather than signing a new one. For an agreement payment, call again without approved: the gate asks the agreement URL unpaid and goes on once it answers 200 with the receipt, or declines agreement-pending again while it answers 202, signing nothing. Never call again with approved for the same agreement: every call with approved signs and sends a new agreement payment.

Detail codes the gate writes

Most refusal codes in detail come from the binding in @integraledger/lcp, which documents them. These are the ones the gate itself writes:

DetailMeaning
<protocol>/no-payable-optionNo option or challenge serves the signer's account. An MPP challenge the protocol package's checks refuse serves none, whatever their refusal code: transact, confirm and within pass over it. within reads a challenge that names the held channel without those checks, and declines its faults as this page lists them.
<protocol>/input-missingA value the build reads from inputs is absent or of the wrong form. See rails.
<protocol>/input-malformedtransact's or agree's options, or a session's inputs, are malformed, the inputs given to confirm, agree or within are not an object, the account of the signer or agreement signer given to transact or agree is not a string, or a Solana refund value, or a Solana refund's paymentResponse or its errorReason, is given in another form. See refunds.
<protocol>/choice-malformedThe chosen handed to finish does not carry the choice the pairing built from.
<protocol>/signature-malformed, mpp/credential-malformedThe signer's answer is not of the form the request kind takes. See signers.
<protocol>/build-failedThe binding's build threw.
<protocol>/link-not-https, <protocol>/legal-context-malformedThe link or agreement URL is not an https URL.
x402/option-not-in-documentThe option of an approved agreement payment is not one of its payment request's accepts, compared by RFC 8785 form, as the protocol package's build holds a chosen option to the document.
x402/payment-identifier-unwritableThe seller advertises x402's payment-identifier extension, and its info is not an object or already holds an id.
x402/payload-malformedA rail's completed payment is not of the form the pairing's payload takes.
mpp/request-malformedAn MPP challenge's request is not base64url JSON with a decimal amount.
mpp/opaque-malformedA session's within challenge carries an opaque that is not MPP's flat string-to-string map: base64url without padding, at most 8 KiB decoded, one JSON object whose members are all strings.
mpp/within-action-not-builtThe in-session action (a top-up, for example) is not one the binding builds.
hedera/tx-mismatchA pushed Hedera transaction id does not name the body's payer and valid start.
ln/preimage-malformedThe Lightning node's answer is not a 64-digit hex preimage.
ln/request-hash-mismatchx402's request hash, recomputed from your request input, is not the option's extra.requestHash or the invoice's description hash.
ln/request-binding-malformed, ln/request-resource-mismatch, ln/request-server-mismatch, ln/request-profile-mismatch, ln/invoice-malformedYour request input, or the option's invoice, does not match the Lightning option it is for.
Edit on GitHub

Last updated on

On this page