Overview
A recipe is one JSON object. Itskind decides which fields apply:
The JSON Schema at
schema/recipe.schema.json in the
public registry repository is
the formal definition. A field that is not listed for a kind is rejected. The
one exception is an optional $schema pointer for editor tooling, which must be
exactly ../../schema/recipe.schema.json.
Fields every recipe shares
string
required
Lowercase, matching
^[a-z0-9][a-z0-9.-]*$. A merchant or signup uses its
primary host. A platform uses its platform slug.string
required
verified, partial, unverified or dead-end. See
Recipe statuses.string
A date in
YYYY-MM-DD form. Required when status is verified.string
How the verification was proven. Required when
status is verified. Up to
2,000 characters.string[]
Things that will catch out the next agent. One sentence each, describing
something you actually observed. Up to 50 entries of up to 1,000 characters.
string[]
Gates the next agent can clear before checkout starts. For checkout recipes:
delivery_location, region_select or account_required. No repeats. Omit the
field rather than sending an empty array. Unlike deadEnd, a precondition
never makes a store unusable.string
Free text for judgement that does not fit a field, for example whether a
blocker is the platform’s or the store’s choice. Up to 2,000 characters.
Platform recipe
Describes how a whole platform’s checkout works. Platform recipes are shared by every store on that platform, so a maintainer reviews each change.string
required
The literal
"platform".string
required
A human-readable name, for example
"WooCommerce + Stripe". Up to 200
characters.object
required
How to recognise this platform. Include at least one of the four signals.
string
required
Where the card fields live. One of
stripe-payment-element, stripe-split,
shopify-card-fields, direct-inputs or varies.string
required
Where the security code goes, as a selector of up to 300 characters. Named on
its own because the card fill order depends on it.
object
required
One instruction per checkout phase, up to 1,000 characters each.
object
Named selectors, up to 20. Each name is up to 100 characters. Each value is a
selector or an array of up to 10 fallbacks tried in order. Each selector is up
to 300 characters.
id must be one of the platforms the SDK can execute. See
Supported platforms.
Example
Merchant recipe
Pins down one store.string
required
The literal
"merchant".string[]
required
Every host this store serves from. At least one, up to 50, each up to 253
characters. No
*. wildcards. A host matches itself
and its subdomains. A host may belong to only one merchant recipe, and www.
and a trailing dot are ignored when comparing.string
required
A platform recipe
id, or "custom" for a store on no known platform.string
Overrides the platform’s value when this store differs.
string
Overrides the platform’s value when this store differs. Up to 300 characters.
object
Selector overrides applied on top of the platform recipe’s
selectors, keyed
the same way. Up to 20. Each name is up to 100 characters. Unlike a platform’s
selectors, each value is exactly one non-empty selector string of up to 300
characters: an array of fallbacks is rejected with invalid_recipe. Include
only the ones you actually used.object
Present if, and only if,
status is "dead-end".string
An
http:// or https:// product URL a later run can use to test again. Up
to 2,048 characters.object[]
The ordered steps from the entry URL to the payment page, 1 to 30 of them. Omit
the field rather than sending an empty array. A route is replayed read only, so
no step types anything. See Route steps.
object
How a checkout with no guest path signs in. Allowed only when
preconditions
includes account_required, and rejected otherwise. Signing in comes first:
the checkout route is walked afterwards, in the same browser. A recipe with
account_required and no signIn is still valid.Route steps
Each step is one object with ahost and exactly one of these:
- The first step is always a
urlstep: the entry URL. hostis the one concrete host the step happens on. It must be covered by the recipe’shosts(the host itself or a subdomain of one), so a checkout that hands off to another host lists that host inhoststoo. InsignIn.route,signIn.hostscount as well. IP addresses and private network names such aslocalhostor.internalare rejected.urlishttp://orhttps://, on the step’s ownhost, up to 2,048 characters. Origin and path only: no query string, no fragment and no credentials. A step that needs search parameters reaches them by a click.selectoris up to 300 characters. Aurlstep and amanualstep take no selector.noteis required on amanualstep, up to 500 characters.- Every value is a single line, with no control characters.
Example: a working store
Example: a dead end
Signup recipes
Signup recipes describe a site’s account signup form. They follow the same submission flow as checkout recipes, with their own vocabulary. Their statuses claim an account creation rather than a purchase; see Statuses on a signup recipe.A signup recipe describes a form. It is not permission to open an account.
Creating a login still goes through a signup request the account holder
approves. See Agent signup.
- Field names for
fieldsandoverrides:email,username,password,confirmPassword,fullName,firstName,lastName,dateOfBirth,phone,gender,street1,city,state,zip,countryandsubmit. No other keys. The address keys are named after the address token components, so each one says which address token fills it. ownerStepslists, in order, what the account owner completes after submit:email_code,sms_code,email_linkorcaptcha. Up to 6 entries. Omit the field rather than sending an empty array. Repeats are real: a site that asks for a code, then a CAPTCHA, then a code again is["email_code", "captcha", "email_code"].- Signup preconditions:
region_select,consent_gateormode_toggle. The checkout preconditions are rejected here. - Signup dead end types:
turnstile,captcha,automation-blocked,sso-only,invite-only,phone-required,waitlistorpayment-required. - Signup platform ids:
auth0,workos,okta,cognito,shopify-customer-accounts,shopify-classic-accounts,google-oauthorapple-oauth.
Selector conventions
- Prefer a stable id or class over a text match.
- Use an array as a fallback chain where a platform has changed its markup across
versions. Entries are tried in order. Only a platform’s
selectorsand a signup platform’sfieldstake an array.overrides, on a store or a signup, take one selector per field. - Target a payment iframe by a stable CSS selector. Never rely on enumerating
frames:
list_framesis refused once a token has been filled.
What a recipe may not contain
Screening rejects a submission that contains any of these.
Full rules and rejection reasons: Contribute a recipe.
Validation rules
The schema checks each recipe on its own. These registry-wide rules are checked as well:idis unique within its family (checkout or signup).- A host is claimed by at most one recipe in its family.
- A merchant’s
platformnames an existing platform recipe, or"custom". - A signup’s
platformnames an existing signup platform recipe, or"custom". verifiedrequiresevidenceandlastVerifiedAt.deadEndandstatus: "dead-end"always appear together.signInappears only whenpreconditionsincludesaccount_required.- Every
routeandsignIn.routestep’shostis covered by the recipe’shosts(plussignIn.hostsfor a sign-in), and the first step is aurlstep.
An editor-only
$schema pointer, and any nested $comment, are removed when the
API parses a submission. Leaving them in your file is fine.