Skip to content

Developer docs

API reference

The Clickless Agent API, version 1. Requests and responses are JSON. The OpenAPI 3.1 description is the source of truth: download openapi.yaml.

Basics

  • Base URL: https://api.getclickless.ai. Paths start with /v1.
  • Auth: Authorization: Bearer ck_live_…, a key for one agent from the developer portal. Production accepts live keys only.
  • Rate limit: per key, 120 requests a minute. Over it you get 429 with Retry-After in seconds.
  • Every response carries X-Request-Id, and every error body its request_id. Quote it when you contact Clickless.
  • Retries are safe: approve and handoff are idempotent per token, and report per brand, order and agent. Idempotency-Key is accepted on every POST, though responses aren’t replayed from it. Retrying a search issues fresh tokens, which is harmless.
  • Money is integer cents with an explicit currency. Text fields must be well-formed text without control characters.

Errors

One shape everywhere:

Error
{
"error": {
"code": "token_expired",
"message": "Attribution token is past its 60-day window",
"request_id": "req_NUpB9LgJrk6iwEtA"
}
}
invalid_request400
A field is missing, malformed, too long, or holds control characters.
unauthorized401
The API key is missing, wrong, revoked, or for the other environment, or it’s a live key and its agent isn’t approved for live traffic.
agent_suspended401
The key’s agent is suspended.
not_found404
No such offer, token or conversion for your agent.
not_approved409
Checkout handoff before the person’s approval was recorded.
checkout_unavailable409
The brand’s checkout can’t take this offer right now.
token_expired410
The attribution token is more than 60 days old. Search again.
payload_too_large413
The request body is over 64 KiB.
rate_limited429
Too many requests for this key. Wait for Retry-After seconds.
internal_error500
Something failed on Clickless’s side. Retry; quote the request id if it persists.

Offers

Request

intentstring, 2–500 · required
What the person wants, in their words. The need only: no names, emails, phone numbers or addresses.
ship_to.countrystring, ISO 3166 alpha-2 · required
The country it ships to.
ship_to.regionstring
State or province code.
ship_to.postal_codestring
Postal code.
budget_centsinteger
The most the person wants to spend.
constraints.categoriesstring[]
Limit to these categories.
constraints.exclude_brandsstring[]
Brands to leave out.
constraints.age_verifiedboolean
True only when you’ve verified the person’s age; age-gated offers need it.
user_context.user_refstring
Your pseudonymous id for the person, hashed with your agent’s key and never stored raw.
limitinteger, 1–10, default 3
Offers and stores together. Show three at most.
include_storesboolean
Also return whole stores in stores when products don’t fill the limit. A store has no price; its link lands on the store. Left out, it’s on for agents Clickless operates and off for yours.
all_categoriesboolean, default false
For agents Clickless operates: search every category, not just the agent’s own. It changes nothing for other agents.

Response: each offer

offer_iduuid
The offer.
productobject
id, title, description, images, price_cents, currency, availability, category_path.
brandobject
id, name, domain, and affiliated (owned by Clickless or its founder).
price_centsinteger
Price after the deal, before tax and shipping. The full price when the brand’s checkout takes the deal off itself.
dealobject
type (percent_off, fixed_off, free_shipping, bundle, subscribe_save, first_order, cpa), a summary to show as returned (it names any code the person types at checkout), and ends_at.
commission_previewobject
What you’d earn at this price: agent_share_cents, currency, basis (percent or cpa), and paid_by (brand, or network: your share is of what the network pays Clickless).
trust_scorenumber, 0–1
Neutral (0.5) for every brand today. Scoring from the brand’s fulfillment, return and dispute record comes next.
regulated_tierboolean
Regulated category: describe it in the brand’s words only, with no claims.
regulated_categorystring or null
Which one, for example health.
no_health_claimsboolean
The brand allows no health claims; the product description is withheld.
sponsoredboolean
Paid placement. Label it.
disclosure_textstring
Show it with the offer. Always present.
attribution_tokenstring, 22 chars
Attributes a sale to this search. Valid for 60 days.
checkoutobject
method (always link today; ACP and UCP sessions come next) and url, a go.getclickless.ai link to the brand.

GET/v1/offers/{offer_id}: One offer’s current price, deal and availability, without a token.

product_iduuid, query
Price against this product. Defaults to the cheapest eligible one.
age_verifiedboolean, query
Required true for age-gated offers.

Returns the same fields as a search offer, without attribution_token and checkout. To show it to a person, search again.

Approval and checkout

POST/v1/attribution/approve: Records that the person approved one offer. Call it only after they say yes.

tokenstring · required
The offer’s attribution_token.
mandate_refstring
AP2 mandate id, when the purchase is authorized through AP2.
cap_centsinteger
A spending cap the person set.

Returns token, approved_at, mandate_ref and cap_cents. The first approval stands; repeating it is safe.

POST/v1/checkout/handoff: The brand’s checkout for an approved offer.

tokenstring · required
An approved attribution_token.

Returns method, url, session_id (null today; reserved for ACP or UCP sessions), discount_code (your per-agent code, when the brand uses codes) and token. Before an approval it answers 409 not_approved. The brand’s checkout charges the card; Clickless never does.

Conversions

POST/v1/conversions/report: Reports an order, for integrations whose brand orders don’t reach Clickless on their own.

tokenstring · required
The attribution_token the order came from.
external_order_idstring · required
The brand’s order number, from the confirmation.
gross_centsinteger · required
Order total in cents.
currencystring, ISO 4217 · required
The order’s currency.

Answers 202 with a status: pending_match, matched, not_matched or duplicate. A report is a claim: it earns nothing unless the brand’s own records match the order.

GET/v1/conversions: Your agent’s conversions, newest order first.

periodstring, query
A month (2026-10) or ISO week (2026-W40), by order date. Omit for all.
limitinteger, 1–100, default 50
Page size.
cursorstring
next_cursor from the previous page.

Each conversion has conversion_id, status (matched, disputed, reversed), match_method, the brand, the order (number, gross, currency, date) and agent_net_cents, your share net of refunds so far.

GET/v1/conversions/{conversion_id}: The audit chain for one conversion, the same one the brand sees.

From the search to the payout: the query (only intent words that also appear in the product’s text), the offers shown by position, the approval, each checkout handoff and click, the order and its refunds, how it was matched, every ledger entry in signed cents, and the part of each payout that came from it. Other brands’ offers in the same search show only their position and whether they were sponsored.

Earnings and account

GET/v1/earnings: Accrued, pending, payable, in transit and paid, for one period.

periodstring, query
A month (2026-10) or ISO week (2026-W40). Defaults to the current month.
currencystring, query
Defaults to USD.

Returns period, currency, accrued_cents, pending_cents, payable_cents, available_cents (the same amount as payable_cents), in_transit_cents, paid_cents, referral_cents and next_payout_on. Earnings and payouts explains each one.

GET/v1/picks: Creators’ picks: the live offers creators approved for their own Product Experts.

creatorstring, query
A creator agent’s handle. Omit for every creator.
categorystring, query
A brand category, such as hydration, sleep, skincare or pet.
limitinteger, 1–50, default 20
How many picks.

Each pick has the creator (handle, name, page and verified Instagram), the brand, its category, the deal, a product to show, sponsored and disclosure_text, which you show with it. To send someone who wants a pick, use its ask_url: the creator’s own agent, which earns the creator the commission. Health and age-gated offers aren’t listed.

GET/v1/me: The agent your key belongs to.

Returns id, name, owner_type, status (sandbox, live, producing, suspended), categories and payouts_ready, true once payout setup and tax details are complete.

Product Experts for stores

POST/v1/brand-agents/provision: Drafts a store’s Product Expert from its URL, for its owner to claim. Takes a developer agent’s key.

store_urlstring · required
The store’s own website. Not a marketplace or site-builder address.
brand_namestring
The store’s name, when the site doesn’t show it clearly.
contact_emailstring
Only when the store’s owner asked for the claim link by email. One email; the address isn’t kept.

Returns the draft: preview_url (private, marked Preview), claim_url for the store’s owner, product_expert with its handle for the widget, what was learned, the final check (test) run in sandbox, pricing to relay word for word and next_steps. 201 when created; 200 with the store’s existing draft, so calling again checks on the test. The draft isn’t public, sends no messages and earns nothing until its owner claims it with proof of control. Errors: 403 not a developer key, 409 already on Clickless, 422 refused, 429 the key’s 20 new stores a day, 503 the day’s spend limit. Add a Product Expert to a store walks through it.