Issue
Assemble, store and hash the ATR for one checkout state, and get the values to place.
POST /issue runs before the buyer approves. The door assembles the ATR from what you send, writes its bytes to the
seller's storage, hashes them, and answers with the values to place in the payment request.
The request
| Field | Required | What to send |
|---|---|---|
mintRequestId | yes | One state of one checkout: <checkout id>:<version>, matching ^[A-Za-z0-9._:-]{1,128}$. |
resource | yes | The resource id declared for the tenant, 1 to 512 characters. |
lifetimeSeconds | yes | The challenge's lifetime, 1 to 604 800. On x402, the largest maxTimeoutSeconds of the offers. |
offers | yes | 1 to 16 {pairing, option}, each option exactly as the challenge will carry it, all of one protocol. |
content | no | 0 to 56 {slot, bytes}: the parties' content, each slot one JSON value as padded base64 of its exact bytes. |
request | on x402 | {method, path, query, bodyDigest}: the request the challenge answers. |
Slot names match ^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$. atrVersion, id and the binding's slot (such as x402) are
reserved. A slot's bytes must be exactly one JSON value (RFC 8259): the door writes them into the ATR as received.
The request commitment
On x402, request commits the ATR to the HTTP request its options answer:
method: the method token, such asGET;path: the request-target up to its first?;query: what follows the first?, or"";bodyDigest:0xand the SHA-256 hex of the body bytes as received. An empty body gives0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
import { } from "node:crypto";
import type { RequestCommitment } from "@integraledger/agentic-connectors";
/** The commitment for a request as received: its method, raw target and body bytes. */
function (: string, : string, : ): RequestCommitment {
const = .("?");
return {
,
: === -1 ? : .(0, ),
: === -1 ? "" : .( + 1),
: `0x${("sha256").().("hex")}`,
};
}
.(.(("GET", "/v1/report", new ())));
.(.(("POST", "/v1/quote?region=eu", new ().('{"n":1}'))));{"method":"GET","path":"/v1/report","query":"","bodyDigest":"0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
{"method":"POST","path":"/v1/quote","query":"region=eu","bodyDigest":"0x2bfd14f43d17fc7cea24e0917a8879b4b2f880b8baeec1b9d90fbaad655e71bd"}@integraledger/lcp computes the same commitment (requestCommitment in @integraledger/lcp/x402); use either.
The answer
| Field | Meaning |
|---|---|
atrHash | H: 0x and 64 lowercase hex digits. |
link | The https URL where the seller's storage serves the ATR. Show this link; never build one. |
expiresAt | When the challenge lapses. |
mintRequestId | The id you sent. |
carriers | H and the link in each carrier form: lcp (lcp:sha256:0x…), legalContext ({type, value, legalContextUrl}) and legal_context ({type, value, legal_context_url}). |
pairings | Each offered pairing with its pattern: how it carries H, and what a record of it proves. |
agreement | Present when the record needs the agreement step: {url, network, pairing}. See the agreement step. |
Retries and changes
The same mintRequestId with the same input returns the first answer, byte for byte, and writes no second file
(vector CV2):
import { } from "@integraledger/agentic-connectors";
const = .. ?? "https://seller.example/door";
const = .. ?? "";
async function (: unknown): <{ : number; : string }> {
const = await (`${}/issue`, {
: "POST",
: { : `Bearer ${}`, "content-type": "application/json" },
: .(),
});
return { : ., : await .() };
}
const [, ] = ["CV2"]!.;
const = await (!..);
const = await (!..);
.(., ., . === .);
// CV3: the same id with a changed amount is refused.
const = await (["CV3"]!.[1]!..);
.(., (.(.) as { : string }).);200 200 true
409 issue/mint-request-reusedA changed checkout gets a new id. When an id's record has lapsed, the door answers 409 issue/mint-request-lapsed:
append :<n> with a new n and issue again.
Failure modes
422: the request cannot be served as sent. The most common areissue/pairing-not-served(the resource does not serve that pairing),issue/offer-refused(the pairing cannot place H in that option; the sentence names the pairing and its code),issue/mixed-protocols, and thecore/…codes for content.503:issue/storage-unavailablemeans the ATR could not be written, so no challenge may go out. Every503carriesRetry-After: 1; retry the same request, with the samemintRequestId.
Whatever the failure, the checkout path stops: a connector never completes a sale without the values issue returns
(rule 5).
Last updated on