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/merchantsList 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
| Name | Type | Description |
|---|---|---|
| q | string | Free-text match on name or domain. Omit to list. |
Responses
200Matching merchants (max 50)
| Field | Type | Description | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| merchants | object[] | show nested schemaarray of
| ||||||||||||||||||||||||
| query | string |
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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
| Name | Type | Description |
|---|---|---|
| id* | string |
Responses
200Merchant metadata
object
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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/quotePrice 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 *
| Field | Type | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| merchant_id* | string | ||||||||||
| items* | object[] | show nested schemaarray of
| |||||||||
| fulfillment_option_id | string | The chosen option's id, from a previous call's `fulfillment_options`. | |||||||||
| pickup_location | string | The branch the user named, in their words. Matched against the merchant's live store list. | |||||||||
| pickup_location_id | string | Preferred over the name when you have it — a Shopify Location gid, matched by exact equality. | |||||||||
| ship_to | object | Deliver to someone who is not the cardholder. Shopify rail only; cannot be combined with pickup. | |||||||||
| constraints | object | 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
|
Responses
200The priced cart
| Field | Type | Description | |||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| rail | string | example: "shopify" | |||||||||||||||||||||||||||
| fulfillment_options | object[] | show nested schemaarray of
| |||||||||||||||||||||||||||
| requires_fulfillment_choice | boolean | True when there is a real choice and none was made. The amount is withheld until it is. | |||||||||||||||||||||||||||
| selected_option_id | string | ||||||||||||||||||||||||||||
| expected_amount_minor | integer | The figure to pass to dispatch. Null while a choice is outstanding. | |||||||||||||||||||||||||||
| amount_is_final | boolean | 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_minor | integer | ||||||||||||||||||||||||||||
| charge_estimate_minor | integer | ||||||||||||||||||||||||||||
| charge_cap_minor | integer | ||||||||||||||||||||||||||||
| currency | string | ||||||||||||||||||||||||||||
| basket_url | string | The same cart on the merchant's own site, for the user to inspect. If they pay there, do not also place the order. | |||||||||||||||||||||||||||
| lines | object[] | show nested schemaarray of object | |||||||||||||||||||||||||||
| ship_to | object | Echoed back redacted. Present only when a destination was supplied. | |||||||||||||||||||||||||||
| ship_to_sha256 | string | Digest of the destination this quote was priced for. | |||||||||||||||||||||||||||
| billing_uses_ship_to | boolean | When true, the merchant will see the delivery address on the card too. Say so before the user approves. | |||||||||||||||||||||||||||
| constraints | object | circular show nested schemaobject — circular | |||||||||||||||||||||||||||
| unfulfillable | object | 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
| |||||||||||||||||||||||||||
| pickup_resolution | object | 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
|
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
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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/cardsThe 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
| Field | Type | Description | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| cards | object[] | show nested schemaarray of
|
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
Example (cURL)
curl -X GET 'https://api.agnic.ai/api/autofill/cards' \
-H 'X-Agnic-Token: YOUR_TOKEN'GET
/api/autofill/products/searchSearch 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
| Name | Type | Description |
|---|---|---|
| q* | string | What 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. |
| limit | integer default: 20 |
Responses
200Matching products, buyable first and cheapest first within that
| Field | Type | Description | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| query | string | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| country | string | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currency | string | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shops_searched | integer | How many vetted shops this query actually covered. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chunks | integer | Catalogue calls made. More than one means the pool exceeds the per-call ceiling. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| price_note | string | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
| products | object[] | show nested schemaarray of
|
400`missing_query`, or `unsupported_country` with the list of markets that do work.
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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/lookupResolve 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
| Name | Type | Description |
|---|---|---|
| url* | string<uri> | A Shopify product page URL, e.g. https://shop.example/products/handle?variant=41550442692800 |
Responses
200The resolved variant
| Field | Type | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| sku | string | Pass this straight to a quote as the item sku. | ||||||||||||
| title | string | |||||||||||||
| variant_title | string | |||||||||||||
| price_minor | integer | |||||||||||||
| currency | string | |||||||||||||
| available | boolean | |||||||||||||
| merchant | object | show nested schema
| ||||||||||||
| onboard | object | Present only when the shop is not yet a merchant. Call explore with this URL. show nested schema
| ||||||||||||
| variant_note | string | Present when the URL named no variant and one was chosen for you. | ||||||||||||
| price_note | string |
400`missing_url`, or `not_a_product_url` — the link is a shop or a collection, not an item.
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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/dispatchPlace 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 *
| Field | Type | Description | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| merchant_id* | string | |||||||||||||||||||||||||
| items* | object[] | show nested schemaarray of
| ||||||||||||||||||||||||
| amount_minor* | integer | The bound figure from the preview response — not what you originally asked for. | ||||||||||||||||||||||||
| currency | string | example: "GBP" | ||||||||||||||||||||||||
| card_alias_id | string | 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_prompt | string | The user's ORIGINAL request, not their yes. Shown on the receipt and the dispute bundle. | ||||||||||||||||||||||||
| approval_token | string | Present only when retrying after a step-up approval. | ||||||||||||||||||||||||
| fulfillment_option_id | string | |||||||||||||||||||||||||
| pickup_location | string | |||||||||||||||||||||||||
| pickup_location_id | string | |||||||||||||||||||||||||
| ship_to | object | 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
| ||||||||||||||||||||||||
| constraints | object | 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
|
Responses
200Dispatched. Poll the order.
| Field | Type | Description |
|---|---|---|
| order_id | string | |
| status | string | example: "dispatched" |
| worker_job_id | string | |
| order_url | string | 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_url | string | The underlying signed, TTL-bound stream that `order_url` embeds. Prefer `order_url`. |
202A passkey approval is required before this can proceed.
| Field | Type | Description |
|---|---|---|
| approval_required | boolean | |
| approval_token | string | |
| approval_url | string | |
| expires_in | integer | |
| reason | string |
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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/exploreOnboard 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 *
| Field | Type | Description |
|---|---|---|
| merchant_url* | string<uri> | |
| goal* | string | What to buy |
| prefs | string | Fulfilment preference |
| currency | string |
Responses
200Discovery started or completed
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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/ordersRecent orders for the authenticated user
Auth:ApiTokenOAuth2
Responses
200Up to 50 orders, newest first
| Field | Type | Description |
|---|---|---|
| orders | object[] | show nested schemaarray of object |
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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
| Name | Type | Description |
|---|---|---|
| id* | string |
Responses
200The order
| Field | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| id | string | |||||||||||||||||||
| merchant_id | string | |||||||||||||||||||
| status | string | Live — `pending`, `dispatched`, `approval_required`.
Terminal — `succeeded`, `merchant_error`, `worker_error`,
`price_changed`, `out_of_stock`, `payment_unconfirmed`,
`payment_gate_hit`, `timeout`, `explored`.
| ||||||||||||||||||
| amount_minor | integer | The APPROVED figure — a ceiling on tax-added markets. | ||||||||||||||||||
| amount_charged_minor | integer | What the merchant's own page said. Report THIS to the user; it can be below the approved figure. | ||||||||||||||||||
| currency | string | |||||||||||||||||||
| retryable | boolean | 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_code | string | |||||||||||||||||||
| error_message | string | |||||||||||||||||||
| ship_to | object | |||||||||||||||||||
| constraints | object | |||||||||||||||||||
| test | boolean | Placed at a test store. No real money moved. | ||||||||||||||||||
| evidence | object | show nested schema
| ||||||||||||||||||
| live_view_url | string | Watch the checkout run, and the surface a human uses if a step-up appears. |
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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}/evidenceDispute-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
| Name | Type | Description |
|---|---|---|
| id* | string |
Responses
200The bundle
401Unauthorized - invalid or missing authentication
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
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/reliabilityPer-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
| Field | Type | Description |
|---|---|---|
| error | string | |
| error_description | string | |
| message | string |
Example (cURL)
curl -X GET 'https://api.agnic.ai/api/autofill/reliability' \
-H 'X-Agnic-Token: YOUR_TOKEN'