Skip to content
Integra Agentic Connectors

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

FieldRequiredWhat to send
mintRequestIdyesOne state of one checkout: <checkout id>:<version>, matching ^[A-Za-z0-9._:-]{1,128}$.
resourceyesThe resource id declared for the tenant, 1 to 512 characters.
lifetimeSecondsyesThe challenge's lifetime, 1 to 604 800. On x402, the largest maxTimeoutSeconds of the offers.
offersyes1 to 16 {pairing, option}, each option exactly as the challenge will carry it, all of one protocol.
contentno0 to 56 {slot, bytes}: the parties' content, each slot one JSON value as padded base64 of its exact bytes.
requeston 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 as GET;
  • path: the request-target up to its first ?;
  • query: what follows the first ?, or "";
  • bodyDigest: 0x and the SHA-256 hex of the body bytes as received. An empty body gives 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
commitment.ts
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

FieldMeaning
atrHashH: 0x and 64 lowercase hex digits.
linkThe https URL where the seller's storage serves the ATR. Show this link; never build one.
expiresAtWhen the challenge lapses.
mintRequestIdThe id you sent.
carriersH and the link in each carrier form: lcp (lcp:sha256:0x…), legalContext ({type, value, legalContextUrl}) and legal_context ({type, value, legal_context_url}).
pairingsEach offered pairing with its pattern: how it carries H, and what a record of it proves.
agreementPresent 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):

retry.ts
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-reused

A 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 are issue/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 the core/… codes for content.
  • 503: issue/storage-unavailable means the ATR could not be written, so no challenge may go out. Every 503 carries Retry-After: 1; retry the same request, with the same mintRequestId.

Whatever the failure, the checkout path stops: a connector never completes a sale without the values issue returns (rule 5).

Edit on GitHub

Last updated on

On this page