Skip to main content
shop pay connects a shopper’s shop account through oauth and issues a single-use card for each purchase the shopper approves in shop. KERNEL’s native integration handles the connection, token refresh, approval requests, and card storage through vault items. oauth credentials and card material use kms-backed envelope encryption. use KERNEL’s fill api to inject the approved card into an attached browser without passing its values through your application’s injection code or model context. you provide references and selectors; KERNEL returns outcomes, not the values. shop pay is the wallet provider, not the merchant’s payment processor. the card works on any checkout with supported, uniquely selectable card inputs, so the merchant doesn’t need to be on shopify. use shop pay on card-form checkouts. prefer a site’s own agent checkout when one is available, and don’t fall back to shop pay after another payment method fails. for the overall offering, see payments on KERNEL.

Before you start

shop pay is live only: every approved card is a real card funded by the shopper’s saved payment method, and purchases must be in usd.
the shopper needs a shop account with a saved card. shop pay connects through KERNEL’s shop app only, so there’s no provider configuration to create. create a project-scoped client and vault. the examples below use these kernel and vault variables.

Lifecycle

  1. create a shop pay wallet and present the returned shop_pay_oauth action. the shopper signs in to shop and approves the connection.
  2. require the wallet to be connected.
  3. optionally request the payment_methods expansion and let the shopper choose a saved card. without a choice, shop uses the shopper’s preferred card.
  4. reach the final checkout page in a browser with the vault attached, then create a card item with the purchase details. creating the card doesn’t contact shop.
  5. retrieve the card, verify that it advertises authorize, and once the shopper has confirmed the purchase, invoke it with the browser’s browser_id and the checkout’s exact current top-level page_url. KERNEL confirms the checkout is open, sends that page to shop as the merchant, and asks the shopper to approve the purchase in shop.
  6. complete the returned action: share a spend_approval url unchanged, or for push_approval tell the shopper to approve in the shop app. then wait for state.status to become ready.
  7. fill the checkout within an hour of the card becoming ready, submit it yourself once, then report the merchant’s outcome with confirm_transaction. reporting ends the card.
each item’s available_operations[].description describes the next step and its recovery, so have your agent read it rather than hard-coding the flow.

Connect a wallet

before showing a shop pay connection option, list the vault’s items. if a shop pay wallet already exists in any state, reuse it and show its existing action or status instead. the api makes item keys unique but does not currently enforce one wallet per provider, so the ui must enforce a maximum of one shop pay wallet per vault. the examples use presentProviderAction, an application-owned function that publishes the action to an authenticated session for the shopper who owns the vault. bind the action to that shopper, vault, and item; apply a short application ttl capped by wallet.expires_at; and stop serving it when the action changes or disappears. the sign-in link expires after 10 minutes, and reading the wallet after that returns a new one. derive authenticatedUser from the server-side session, not a request field. do not log the url or put it in model context.
open connection and approval urls in a trusted user-facing surface. don’t give them to the agent or print full wallet responses into model context. run cli --open only from a trusted, human-operated terminal because the command output can contain the action url.
a declined wallet, from a shopper who denied the connection, can’t be reconnected; delete it and create a new one. shop’s refresh tokens last 30 days from the connection, so a shopper reconnects about once a month. when shop stops accepting the grant, the wallet becomes reconnect_required and returns a new shop_pay_oauth action; present it the same way. shop may skip the consent screen if the shopper already approved KERNEL. deleting the wallet deletes its cards, cancels their pending requests, and revokes KERNEL’s access to the shop account. to remove KERNEL from shop’s connected apps, the shopper removes it in shop.

Select a payment method

request payment_methods only when available_expansions advertises it. the expansion comes from shop at request time and is not persisted in the vault item. each method has an id, a display with brand, label (such as Visa •••• 4242), and last4, and is_default for the shopper’s preferred card.
show the returned methods in a trusted user-facing surface and pass the chosen id as the card’s payment_method_id, or omit it to use the shopper’s preferred card.

Create and authorize a card item

create the card once the browser is on the final checkout page and you know the final amount and merchant. the examples use browser, a KERNEL browser created with this vault attached, and checkoutURL / checkout_url, the browser’s exact current top-level checkout url obtained through your browser-control method.
run checkout in a headful browser, or a headless one with at least 2GiB of memory. heavy checkout pages can exhaust a 1GiB headless browser, which then stops responding to KERNEL during authorization and fill.
amount uses minor currency units, so 2306 means 23.06 usd, and is the most the shopper approves. totals needs exactly one entry with type: "total", positive and no higher than amount; entries such as subtotal, tax, fulfillment, or a negative discount describe the purchase. context is shown to the shopper when they approve, so write it for them. see item reference for every limit. until you authorize the card, you can replace its spec with an update. once it is authorized, updates return 409: delete the card and create a new one with the updated details. authorization sends the checkout page to shop as the merchant and limits fill to that page’s origin. authorizing without browser_id and page_url uses merchant_url instead; use it only as a fallback when checkout inspection keeps failing. presentProviderAction shares a spend_approval url with the shopper unchanged. a push_approval has no url: tell the shopper to approve the purchase in the shop app. the shopper has until the card’s expires_at, currently 24 hours after authorization, to approve. an approval link works once: if the shopper opens it again, shop shows the approval as unavailable. retrieve the card and share the url from its current action instead. once approval has been requested, {"type":"authorize"} only re-checks the request and never creates another payment request.

Authorization errors

these errors happen before shop receives a payment request, so the card stays requested and you can authorize again: if shop refuses the request, authorize returns an error with shop’s reason and the card becomes declined: read status_reason, then delete the card and create a new one. if shop rate limits the request (429), the card stays requested; wait for Retry-After, then authorize again. if the shopper declines or the request expires, delete the card and create a new one.

Fill the checkout

after the shopper approves, retrieve the card with wait: 60. continue only when it is ready and advertises fill; one bounded wait may finish before approval does. a ready card’s expires_at is its fill deadline, at most an hour later, so fill and submit promptly. after that the card is expired and can’t be filled, but you can still report its outcome. every fill supplies browser_id, the exact current top-level page_url, and ordered fields bindings. page_url must use https and must be on the origin of the checkout you authorized at, or on the origin of spec.merchant_url for a card authorized without a checkout. the origin includes the host and port and doesn’t allow other subdomains, even though the card’s state.domains lists the registrable domain. a disallowed origin returns 403 destination_denied. for the shared rules, see fill browser fields. billing_name is shop’s cardholder name, or the first and last name joined when shop returns only those. billing_first_name and billing_last_name are available only when shop returns them separately; billing_name is never split. request only needed billing fields. an absent or empty requested billing value returns 400 field_unavailable before any browser writes. supply 1 to 32 ordered bindings, never raw values. format is allowed only on the combined expiration. these selectors illustrate a checkout you control; replace them with selectors verified on your page, including within payment frames.
completed means the fields were filled, not that payment succeeded. fill never submits, so a retry is safe after checking the page, but never in an automatic loop. submit the checkout yourself once. see the shared fill outcome contract for per-field statuses.

Report the outcome

after submitting the checkout and observing the merchant’s result, invoke confirm_transaction once when the card advertises it. reporting ends the card: KERNEL tells shop the outcome, deletes the stored card, and moves the item to consumed whatever the outcome. another attempt needs a new card and a new approval.
report only what the merchant showed. if the outcome is unclear, ask the shopper to check the merchant’s order confirmation or order history, then report what it shows. don’t retry checkout.

Item reference

wallet and card items accept these spec fields. fields not listed here are rejected. a card’s spec.wallet must reference a shop pay wallet in the same vault. amount is 1 to 1000000 minor units, currency is usd, merchant_name is at most 255 characters, merchant_url is an https url with a registrable domain, and context is 100 to 500 characters. merchant_country is a two-letter country code. each line_items entry has name, quantity (at least 1), and unit_amount (at least 0); each totals entry has type and amount.

Item states

  • wallet: pending_authorization, connected, declined, reconnect_required, degraded
  • card: requested, pending_authorization, ready, consumed, expired, declined, recovery_required
declined covers a request the shopper declined, that was cancelled, or that shop refused at authorization. card state can include masks.brand and masks.last4 once shop issues the card. recovery_required means a provider operation has an unresolved outcome and the card can’t be used. when status_reason says shop refused retrieval before acceptance, no card was issued and a later read retries. otherwise follow status_reason: recovery for issuance can be abandoned by deleting the card and creating a new one, which the shopper approves separately. recovery while reporting a merchant transaction can’t be deleted; contact support with the vault, item key, and status_reason. deleting a card cancels its pending shop request and clears its stored card. it doesn’t revoke a card shop already issued.