Agnic
API Reference

Checkout

Buy from merchants that never integrated with anything. Find a merchant, price an order with shipping known up front, place it with a vaulted card, and follow it to a named outcome. Preview never charges; only POST /api/autofill/dispatch spends money.

GET/api/autofill/merchants

List or search merchants

Merchants already in the network. The `rail` decides what is possible: `shopify` merchants quote live prices and real shipping options and accept a delivery address; `worker` merchants price from a cached catalogue. `is_test` marks a store Agnic runs for testing — no real money moves there.
Auth:ApiTokenOAuth2

query parameters

NameTypeDescription
qstringFree-text match on name or domain. Omit to list.

Responses

200Matching merchants (max 50)
FieldTypeDescription
merchantsobject[]
show nested schema
array of
FieldTypeDescription
idstring
namestring
domainstring
railstring
`shopify` — live pricing, real shipping options, accepts a delivery address. `worker` — priced from a cached catalogue, cardholder address only. `acp` — the merchant runs an agentic checkout protocol endpoint.
example: "shopify"
default_currencystring
categoriesstring[]
show nested schema
array of
string
is_testboolean
A store Agnic runs for testing. Shopify Payments in test mode — no real money, no real goods.
querystring
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/merchants' \
  -H 'X-Agnic-Token: YOUR_TOKEN'
GET/api/autofill/merchants/{id}

One merchant, with its catalogue when it has one

Auth:ApiTokenOAuth2

path parameters

NameTypeDescription
id*string

Responses

200Merchant metadata
object
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring
404Merchant not found

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/merchants/{id}' \
  -H 'X-Agnic-Token: YOUR_TOKEN'
POST/api/autofill/shopify/quote

Price a cart, with shipping options, before anything is charged

Builds a live Storefront cart and returns what the order would actually cost, including the merchant's real delivery options. Charges nothing and launches no browser. Two amount semantics, and the difference matters: when `amount_is_final` is true the total is tax-inclusive and `expected_amount_minor` IS the charge. When it is false the merchant adds tax at checkout, and `expected_amount_minor` is a CEILING the real charge stays under. When the merchant offers more than one fulfilment option and none was chosen, `requires_fulfillment_choice` is true and `expected_amount_minor` is withheld — there is no honest amount to bind until the choice is made.
Auth:ApiTokenOAuth2

Request body *

FieldTypeDescription
merchant_id*string
items*object[]
show nested schema
array of
FieldTypeDescription
sku*string
On the Shopify rail this is a variant gid (`gid://shopify/ProductVariant/…`). Elsewhere it is the merchant's own sku. A guess is acceptable — the response returns the nearest real products rather than a bare error.
quantity*integer
fulfillment_option_idstring
The chosen option's id, from a previous call's `fulfillment_options`.
pickup_locationstring
The branch the user named, in their words. Matched against the merchant's live store list.
pickup_location_idstring
Preferred over the name when you have it — a Shopify Location gid, matched by exact equality.
ship_toobject
Deliver to someone who is not the cardholder. Shopify rail only; cannot be combined with pickup.
constraintsobject
Spending limits checked BEFORE any card is used, bound into the confirmation token so they cannot be raised between approval and payment, and re-checked against a fresh cart at dispatch. Minor units of the order currency.
show nested schema
FieldTypeDescription
max_total_minorinteger
Most that may be charged in total.
max_shipping_minorinteger
Most that may be spent on shipping. 0 means free shipping only.

Responses

200The priced cart
FieldTypeDescription
railstring
example: "shopify"
fulfillment_optionsobject[]
show nested schema
array of
FieldTypeDescription
idstring
type"shipping" | "local" | "pickup" | "none" | "other"
`other` is the fallback for any delivery method Shopify offers that Agnic does not recognise, and `none` for a cart that needs no delivery. Both still deliver, so branch on what you EXCLUDE (`pickup`) rather than allow-listing `shipping` and `local` — a new Shopify method would otherwise disappear from your options list.
titlestring
descriptionstring
price_minorinteger
currencystring
requires_addressboolean
etastring
e.g. "Usually ready in 24 hours". Present when the merchant gives one.
requires_fulfillment_choiceboolean
True when there is a real choice and none was made. The amount is withheld until it is.
selected_option_idstring
expected_amount_minorinteger
The figure to pass to dispatch. Null while a choice is outstanding.
amount_is_finalboolean
True — the total is tax-inclusive and this IS the charge. False — the merchant adds tax at checkout and this is a CEILING the real charge stays under. Never present a ceiling as the total.
subtotal_minorinteger
charge_estimate_minorinteger
charge_cap_minorinteger
currencystring
basket_urlstring
The same cart on the merchant's own site, for the user to inspect. If they pay there, do not also place the order.
linesobject[]
show nested schema
array of
object
ship_toobject
Echoed back redacted. Present only when a destination was supplied.
ship_to_sha256string
Digest of the destination this quote was priced for.
billing_uses_ship_toboolean
When true, the merchant will see the delivery address on the card too. Say so before the user approves.
constraintsobject
circular
show nested schema
object — circular
unfulfillableobject
The merchant cannot fulfil this buyer at all — no delivery options and no local collection. An OBJECT, not a boolean: test for its presence. When it is present `expected_amount_minor` is null and `fulfillment_options` is empty.
show nested schema
FieldTypeDescription
reasonstring
pickup_resolutionobject
Which store a collection would come from. Returned whenever the cart resolved pickup at all, including alongside `ship_to` — with a destination it will read `unavailable`, because a delivery rules collection out.
show nested schema
FieldTypeDescription
statusstring
store_countinteger
querystring
storeobject
show nested schema
object
candidatesobject[]
show nested schema
array of
object
suggestionsobject[]
show nested schema
array of
object
400`ship_to_invalid` — `detail` names the field that is missing or malformed. `constraints_invalid` — a cap was not a non-negative integer.
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring
409`ship_to_unsupported` — this merchant's rail cannot verify a delivery address. `ship_to_with_pickup` — an order cannot be both collected and delivered. `constraint_total_exceeded` — carries `max_total_minor` and `expected_amount_minor`. `constraint_shipping_exceeded` — carries `max_shipping_minor`, `shipping_minor`, `option_id`. `constraint_unverifiable` — shipping cannot be priced before checkout on this rail.
422An item's sku matched no live product. The body carries the nearest matches.

Example (cURL)

curl -X POST 'https://api.agnic.ai/api/autofill/shopify/quote' \
  -H 'X-Agnic-Token: YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"key":"value"}'
GET/api/autofill/cards

The cards this user has vaulted

Card numbers never appear here and never reach Agnic's application code: vaulting happens straight into the vault from the browser. What comes back is what you need to choose between cards and nothing more. Omit `card_alias_id` on a dispatch and the default card is used.
Auth:ApiTokenOAuth2

Responses

200The user's vaulted cards, default first
FieldTypeDescription
cardsobject[]
show nested schema
array of
FieldTypeDescription
idstring
Pass as `card_alias_id` on a dispatch.
last_fourstring
brandstring
exp_monthinteger
exp_yearinteger
is_defaultboolean
created_atstring<date-time>
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/cards' \
  -H 'X-Agnic-Token: YOUR_TOKEN'
GET/api/autofill/products/search

Search products across the vetted merchant network

Finds a PRODUCT across thousands of vetted Shopify shops in one market. Read-only: it charges nothing and onboards nothing. Prices are BROWSE-TIME — what the catalogue last saw. `POST /api/autofill/shopify/quote` is the authoritative amount and the only one that accounts for shipping, tax and current stock. A result carrying `onboard` is at a shop Agnic has never bought from. That is normal and is most of the network: call `POST /api/autofill/explore` with that URL first, then quote. The whole approved pool is searched. The catalogue accepts at most 1,000 shops per call and every market is at that ceiling, so this chunks and merges rather than truncating — `chunks` says how many calls it took.
Auth:ApiTokenOAuth2

query parameters

NameTypeDescription
q*stringWhat the user is looking for, in plain product language.
country*"US" | "GB" | "CA" | "AU"The market to search — where the parcel is going, not where the buyer banks. Shops are vetted per country. Anything else returns `unsupported_country`, which is an answer, not a transient error.
limitinteger
default: 20

Responses

200Matching products, buyable first and cheapest first within that
FieldTypeDescription
querystring
countrystring
currencystring
shops_searchedinteger
How many vetted shops this query actually covered.
chunksinteger
Catalogue calls made. More than one means the pool exceeds the per-call ceiling.
price_notestring
productsobject[]
show nested schema
array of
FieldTypeDescription
skustring
The variant gid. Pass verbatim as an item `sku`.
example: "gid://shopify/ProductVariant/41550442692800"
product_gidstring
titlestring
vendorstring
price_minorinteger
Browse-time price in minor units. NOT a quote.
currencystring
availableboolean
image_urlstring
product_urlstring
merchantobject
show nested schema
FieldTypeDescription
namestring
domainstring
merchant_idstring
Null when Agnic has never bought from this shop. Not an error — see `onboard`.
onboardobject
Present ONLY when `merchant.merchant_id` is null. Call explore with this URL to make the shop buyable, then quote.
show nested schema
FieldTypeDescription
merchant_urlstring
400`missing_query`, or `unsupported_country` with the list of markets that do work.
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring
502`catalog_unavailable` — the catalogue did not answer. Do not report this as "the product does not exist".

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/products/search?q=%3Cvalue%3E&country=%3Cvalue%3E' \
  -H 'X-Agnic-Token: YOUR_TOKEN'
GET/api/autofill/products/lookup

Resolve a product URL into something buyable

Turns a product page URL into a `sku`, with the live storefront price and stock. Shopify shops only. **Send the URL exactly as the user copied it.** The `?variant=` parameter is which size or colour they chose. Without one this resolves the first available option and says so in `variant_note` — for a product whose options matter, ask the user to re-copy the link after choosing rather than picking for them. Read-only by design: it never onboards a merchant. A response carrying `onboard` needs `POST /api/autofill/explore` first. A GET that quietly created a merchant record would be a side effect nobody asked for.
Auth:ApiTokenOAuth2

query parameters

NameTypeDescription
url*string<uri>A Shopify product page URL, e.g. https://shop.example/products/handle?variant=41550442692800

Responses

200The resolved variant
FieldTypeDescription
skustring
Pass this straight to a quote as the item sku.
titlestring
variant_titlestring
price_minorinteger
currencystring
availableboolean
merchantobject
show nested schema
FieldTypeDescription
namestring
domainstring
merchant_idstring
onboardobject
Present only when the shop is not yet a merchant. Call explore with this URL.
show nested schema
FieldTypeDescription
merchant_urlstring
variant_notestring
Present when the URL named no variant and one was chosen for you.
price_notestring
400`missing_url`, or `not_a_product_url` — the link is a shop or a collection, not an item.
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring
404`variant_not_found` — the page resolved to no buyable option. Ask for a link with `?variant=`.
409`not_shopify` — use explore with the store URL instead; it works on checkouts Agnic has never seen.

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/products/lookup?url=%3Cvalue%3E' \
  -H 'X-Agnic-Token: YOUR_TOKEN'
POST/api/autofill/dispatch

Place the order — this is the call that spends money

Creates the order and dispatches it. Returns immediately with an `order_id`; the checkout itself takes about a minute. Poll `GET /api/autofill/orders/{id}` until it is terminal. **Never call this twice for the same order.** `ship_to` and `constraints` must be IDENTICAL to the values used at preview. They are part of what the confirmation token binds, so any difference means nothing is charged — which is what stops a destination or a spending limit changing between approval and payment. A `202` with `approval_required` is not a failure: the purchase falls outside the user's standing signed policy and they must approve it with their passkey. Show the URL, poll the approval, then call again with `approval_token`.
Auth:ApiTokenOAuth2

Request body *

FieldTypeDescription
merchant_id*string
items*object[]
show nested schema
array of
FieldTypeDescription
sku*string
On the Shopify rail this is a variant gid (`gid://shopify/ProductVariant/…`). Elsewhere it is the merchant's own sku. A guess is acceptable — the response returns the nearest real products rather than a bare error.
quantity*integer
amount_minor*integer
The bound figure from the preview response — not what you originally asked for.
currencystring
example: "GBP"
card_alias_idstring
Omit to use the default card.
user_confirmation_text*string
The user's literal affirmative reply. Dispute evidence; do not paraphrase it.
user_approved_at_iso*string<date-time>
user_promptstring
The user's ORIGINAL request, not their yes. Shown on the receipt and the dispute bundle.
approval_tokenstring
Present only when retrying after a step-up approval.
fulfillment_option_idstring
pickup_locationstring
pickup_location_idstring
ship_toobject
Where the parcel goes, when that is not the cardholder. ORDER data: it does not change the user's saved address, and the next order goes back to the cardholder unless you say otherwise. Contact details stay the cardholder's, so the merchant's confirmation email reaches the buyer rather than the recipient.
show nested schema
FieldTypeDescription
name*string
street_address*string
address_locality*string
Town or city.
address_regionstring
Province, state or county. REQUIRED for CA, US and AU — their checkouts will not complete without one.
postal_code*string
address_country*string
ISO-3166-1 alpha-2, upper case.
example: "GB"
phonestring
The recipient's phone, when they have one — couriers call the door, not the buyer.
constraintsobject
Spending limits checked BEFORE any card is used, bound into the confirmation token so they cannot be raised between approval and payment, and re-checked against a fresh cart at dispatch. Minor units of the order currency.
show nested schema
FieldTypeDescription
max_total_minorinteger
Most that may be charged in total.
max_shipping_minorinteger
Most that may be spent on shipping. 0 means free shipping only.

Responses

200Dispatched. Poll the order.
FieldTypeDescription
order_idstring
statusstring
example: "dispatched"
worker_job_idstring
order_urlstring
THE link to give the user. It streams the checkout live while the order runs, prompts them in-page if a human step appears, and keeps the receipt and evidence afterwards.
live_view_urlstring
The underlying signed, TTL-bound stream that `order_url` embeds. Prefer `order_url`.
202A passkey approval is required before this can proceed.
FieldTypeDescription
approval_requiredboolean
approval_tokenstring
approval_urlstring
expires_ininteger
reasonstring
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring
409Refused before any card was used, so no charge is possible. `ship_to_unsupported`, `ship_to_with_pickup`, `ship_to_mismatch` (the approved destination is not the one sent), `constraint_violated`, `shopify_amount_changed`, `pickup_location_unresolved`.

Example (cURL)

curl -X POST 'https://api.agnic.ai/api/autofill/dispatch' \
  -H 'X-Agnic-Token: YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"key":"value"}'
POST/api/autofill/explore

Onboard a merchant nobody has bought from before

Drives an unseen merchant's live checkout read-only, stops at the payment step, charges nothing, and records what an order there takes. Slow — allow up to two minutes. Returns an `order_id` of kind `explored`; poll it.
Auth:ApiTokenOAuth2

Request body *

FieldTypeDescription
merchant_url*string<uri>
goal*string
What to buy
prefsstring
Fulfilment preference
currencystring

Responses

200Discovery started or completed
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring

Example (cURL)

curl -X POST 'https://api.agnic.ai/api/autofill/explore' \
  -H 'X-Agnic-Token: YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"key":"value"}'
GET/api/autofill/orders

Recent orders for the authenticated user

Auth:ApiTokenOAuth2

Responses

200Up to 50 orders, newest first
FieldTypeDescription
ordersobject[]
show nested schema
array of
object
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/orders' \
  -H 'X-Agnic-Token: YOUR_TOKEN'
GET/api/autofill/orders/{id}

One order, with the failure contract

Poll this while an order is in flight. Once terminal it carries `retryable` and `retry_action`, which exist so you never have to pattern-match an error code.
Auth:ApiTokenOAuth2

path parameters

NameTypeDescription
id*string

Responses

200The order
FieldTypeDescription
idstring
merchant_idstring
statusstring
Live — `pending`, `dispatched`, `approval_required`. Terminal — `succeeded`, `merchant_error`, `worker_error`, `price_changed`, `out_of_stock`, `payment_unconfirmed`, `payment_gate_hit`, `timeout`, `explored`.
amount_minorinteger
The APPROVED figure — a ceiling on tax-added markets.
amount_charged_minorinteger
What the merchant's own page said. Report THIS to the user; it can be below the approved figure.
currencystring
retryableboolean
True — placing again is safe; the evidence proves the card was never submitted. False — it will fail the same way, or it already succeeded. **Null — nobody knows and money may have moved. Stop.**
retry_action"re_preview" | "poll" | "handoff" | "contact_support" | "none"
The single next call. Branch on this rather than on the error code.
error_codestring
error_messagestring
ship_toobject
constraintsobject
testboolean
Placed at a test store. No real money moved.
evidenceobject
show nested schema
FieldTypeDescription
charge_state"none" | "attempted" | "unknown" | "confirmed"
Whether the card was ever submitted. `none` is the only value that supports a safe automatic retry, which is why `retryable` is only ever true alongside it.
billing_mode"cardholder" | "ship_to"
ship_to_verifiedboolean
The worker read the destination off the checkout before paying.
observed_total_minorinteger
screenshots_countinteger
live_view_urlstring
Watch the checkout run, and the surface a human uses if a step-up appears.
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring
404Order not found

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/orders/{id}' \
  -H 'X-Agnic-Token: YOUR_TOKEN'
GET/api/autofill/orders/{id}/evidence

Dispute-grade evidence bundle

What was asked, what the user approved, the signed mandate chain, how the order was driven, the merchant's own response, and the delivery address in full. Built to be handed to a scheme months later.
Auth:ApiTokenOAuth2

path parameters

NameTypeDescription
id*string

Responses

200The bundle
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring
404Order not found

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/orders/{id}/evidence' \
  -H 'X-Agnic-Token: YOUR_TOKEN'
GET/api/autofill/reliability

Per-merchant success rate

Runs, successes and the resulting pass rate per merchant recipe. Orders placed at test stores are excluded by rule, so this number only ever reflects real purchases.
Auth:ApiTokenOAuth2

Responses

200Per-merchant reliability
401Unauthorized - invalid or missing authentication
FieldTypeDescription
errorstring
error_descriptionstring
messagestring

Example (cURL)

curl -X GET 'https://api.agnic.ai/api/autofill/reliability' \
  -H 'X-Agnic-Token: YOUR_TOKEN'