Skip to main content
POST
Buy a product from a major online retailer and ship it to a US address
Place an order and pay for it per request over HTTP 402 Payment Required. You don’t need a Zinc account or API key. The agent pays max_price + the $1.00 API fee upfront, and anything the order doesn’t use is refunded to the original payment.

How It Works

  1. Send the order — POST /agent/orders with a complete order body and no payment.
  2. Get the challenge — Zinc checks the body and returns 402 with a challenge for every rail: one WWW-Authenticate header per MPP method, plus a PAYMENT-REQUIRED header for x402.
  3. Pay and resubmit — pay on one rail and send the identical request again with the proof header.
  4. Order placed — Zinc verifies the payment and returns 201 with the order and an X-Api-Key header.
This endpoint takes the same OrderCreate body as the standard Create Order endpoint. Only authentication and payment differ. The same limits apply, including at most 10 products per order, and they’re checked before the agent is charged.

Validation before payment

An agent is never charged for an order Zinc would reject:
  • No body, {}, or null — treated as a discovery probe (for example from a service registry) and answered with a 402 at a placeholder amount.
  • A malformed or incomplete body (including invalid JSON) — 422 straight away. No challenge is issued.
  • An order Zinc can’t fulfill (unsupported retailer, unreachable product URL, unsupported shipping country, invalid address) — checked on the paid retry, before the proof is charged, and rejected with 400. The payment is left untouched, so you can fix the order and retry with it.
Send the complete body on the first request. The challenge amount comes from its max_price.

Choosing a rail

By default the 402 lists every rail. Add ?method=stripe, ?method=tempo, or ?method=x402 to get only that challenge. This helps clients that can’t pick one WWW-Authenticate header out of several. An unknown method returns 400 with the available ones in error.details.available.

Responses

402 Payment Required

string
One header per MPP method (stripe, tempo), per RFC 9110 §11.6.1. Your MPP client or link-cli uses it to pay and resubmit.
string
Base64 x402 v2 PaymentRequired envelope, with one accepts[] entry per supported chain.

201 Created

string
API key for the paying agent. Use it to read the order (GET /orders/{id}), cancel it while pending, and register a webhook URL (PUT /webhooks/endpoint). Store it. It’s the only way to follow the order without paying again.
string
MPP receipt for the charge (Link and Tempo).
string
x402 settlement response (x402 only).

409 Conflict

Returned when this payer already placed an order with the same idempotency_key. The check runs after the payment proof is verified but before it’s settled, so retrying a request that timed out never charges twice. The existing order’s id is in error.details.order_id, and the response carries an X-Api-Key header to read it.
See Agentic Purchases for a full walkthrough of paying with Link, MPP, or x402, including the one-command link-cli mpp pay flow.

Headers

authorization
string | null

Query Parameters

method
string | null

Restrict the 402 to a single payment method (e.g. 'stripe', 'tempo', or 'x402'). Omit to advertise every configured method. Use this when your client can satisfy only one rail — it avoids returning multiple WWW-Authenticate challenges, which many HTTP clients mishandle.

Body

application/json

Request model for creating a new order.

products
OrderProduct · object[]
required
Minimum array length: 1
shipping_address
Address · object
required

Shipping address model.

Supports international addresses. The state field is optional for countries that don't use states/provinces. The country field uses ISO 3166-1 alpha-2 country codes (e.g., "US", "CA", "GB", "DE"), which are required rather than inferred — a longer spelling like "USA" is rejected with the code to use, so everything downstream can rely on seeing alpha-2.

max_price
integer
required

Maximum price (in cents) allowed for an order before it is finalized.

Required range: x >= 0
idempotency_key
string | null

Optional idempotency key to prevent duplicate orders. If not provided, one will be generated.

Maximum string length: 36
retailer_credentials_id
string | null

Optional short ID (e.g. 'zn_acct_XXXXXXXX') of one of your own saved retailer accounts to place this order on. The item is then paid for by the payment method saved on that account, and your wallet is charged the API fee only — so the balance needed to place the order is the fee, not max_price + fee. Omit it and the order is placed on a Zinc account and funded from your wallet; Zinc never substitutes one of your saved accounts, so send this field on every order that has to run on yours.

metadata
Metadata · object | null

Optional metadata to attach to the order. Can contain arbitrary key-value pairs.

po_number
string | null

Optional purchase order number for the order.

handling_days_max
integer | null

Optional ceiling on a seller's shipping and handling days. Omit or send null for no limit.

Required range: x >= 1
is_gift
boolean
default:false

Mark the order as a gift, suppressing prices on the packing slip. If the retailer's checkout offers no free gift option, the order FAILS with gift_option_unavailable rather than being placed as a normal order — a gift that arrives with prices visible to the recipient is treated as worse than no order.

gift_message
string | null

Optional note for the recipient, entered into the retailer's gift-message field at checkout. Requires is_gift to be true. Max 240 characters. Delivered where the retailer's checkout offers a gift message; the order is still placed without it where one isn't available.

Maximum string length: 240
payment
OrderPayment · object | null

Optional payment block. Omit for prepaid-wallet billing (default).

customer_notifications
CustomerNotifications · object | null

Opt in to emailing the end customer order updates (and unlock the public tracking page for this order). Adds a per-order surcharge. Omit for no customer notifications (default).

fulfillment
FulfillmentPreferences · object | null

Loosen the order's strict-by-default rules. Omit for today's behaviour: any rule that can't be met fails the order. Set a rule (gift, items, quantity) to best_effort to have the order placed anyway; anything left unset stays strict. Whatever was relaxed is reported back in fulfillment.concessions on the order. max_price is never relaxed. excluded_merchants tightens instead: merchants this order must not be bought from.

Response

Successful Response

Response model for order data.

id
string<uuid>
required
status
enum<string>
required
Available options:
pending,
in_progress,
order_placed,
order_failed,
cancelled,
cancelled_by_retailer
max_price
integer
required
attempts
integer
required
items
OrderItemResponse · object[]
required
shipping_address
Shipping Address · object
required
retailer_credentials_id
string | null
required
created_at
string<date-time>
required
updated_at
string<date-time>
required
metadata
Metadata · object
po_number
string | null
handling_days_max
integer | null
is_gift
boolean
default:false
gift_message
string | null
retailer_credentials_uuid
string | null
job_result
OrderJobResult · object | null

Fulfillment result and price breakdown for a completed or failed order; null while processing.

merchant_order_ids
string[]

The retailer's own order number(s) for this order (e.g. an Amazon 113-… ID), as recorded when it was placed. Empty while processing, or if the order never reached the retailer.

tracking_numbers
TrackingNumberResponse · object[]
created_by
string | null
user_id
integer | null
returns
ReturnRequestSummary · object[]
cases
CaseSummary · object[]

Support cases on this order, newest first. See /cases.

connect
OrderConnectInfo · object | null

Stripe Connect charge details when this order was paid via Connect; null for prepaid-wallet orders.

payment
OrderPaymentInfo · object | null

Card hold details when this order was paid by card outside the wallet and Connect; null for wallet and Connect orders.

customer_notifications
CustomerNotificationStatus · object | null

End-customer email-notification status when the order opted into the notifications add-on; null when it didn't.

fulfillment
OrderFulfillment · object

gift/items/quantity: the mode this order asked for on each rule (all null = strict). concessions: every rule that actually was relaxed, with the worker's code and the item it concerned. Empty concessions means the order was fulfilled exactly as requested.