diff --git a/browsers/enable-payments-in-browser-agent.mdx b/browsers/enable-payments-in-browser-agent.mdx index db1730a..f69450f 100644 --- a/browsers/enable-payments-in-browser-agent.mdx +++ b/browsers/enable-payments-in-browser-agent.mdx @@ -23,7 +23,7 @@ credential is created and when the user approves it: | card source | provider-minted, one-use card for a specific purchase | user's enrolled card, represented by a reusable card item | | approval timing | before the browser submits checkout | after the browser submits checkout and while the request is held | | reuse | card item and aliases are consumed after the first native handoff | card item and aliases return to `ready`; every checkout requires approval | -| mode | live only | deployment credential; the vault api doesn't expose sandbox or live mode | +| mode | live only | credential-defined; customer-owned configs expose `test_mode` | agentcard is backed by a card the user enrolls, but the agent and browser still enter aliases rather than the underlying card details. those details remain @@ -141,7 +141,11 @@ this guide starts after you have an existing browser agent. it changes how you p - set `KERNEL_API_KEY` and `KERNEL_PROJECT_ID` in the trusted controller that creates your browser. - use a low-value web checkout you control whose outgoing payment request matches a [native processor adapter](/integrations/payments/overview#checkout-and-processor-coverage). the merchant processor doesn't need to be stripe. - link card creation is live-only. agentcard mode comes from the integration's configured credential. -- for agentcard, keep an application-owned `AGENTCARD_MODE` deployment setting and fail closed unless it explicitly matches the sandbox or live environment you intend to use. the vault api does not return this mode. +- for agentcard, keep an application-owned `AGENTCARD_MODE` setting and verify it against the credential's mode. customer-owned configs return `test_mode` (`true` means sandbox); for KERNEL-managed credentials, confirm the deployment's mode. fail closed if the mode is unknown or mismatched. + +use KERNEL-managed credentials by default. optional client setup belongs in your +trusted backend, not the browser agent: see [link](/integrations/payments/stripe-link#bring-your-own-link-oauth-client) +or [agentcard](/integrations/payments/agentcard#bring-your-own-agentcard-oauth-client). keep wallet collection and payment approval outside the agent. show hosted @@ -634,6 +638,7 @@ use item state, item events, the checkout page, and the merchant's order record | link `consumed`, `credential_submitted`, or `credential_tokenized` | confirm processor and merchant state; credential use alone does not prove purchase success | | agentcard `ready` or authorization `approved` | inspect charge, replay, and merchant state; reusable item state does not prove purchase success | | decline, expiry, rejection, failure, abandonment, or `payment_unknown` | stop and reconcile the existing attempt before deciding whether a new purchase is appropriate | +| `recovery_required` | stop; reconcile the unresolved provider outcome. do not retry or delete the item or its parent wallet/vault | use the merchant order record as the authority for whether the expected order was created and paid. require its merchant, amount, currency, and items to match diff --git a/integrations/payments/agentcard.mdx b/integrations/payments/agentcard.mdx index 5e1b3cf..3553511 100644 --- a/integrations/payments/agentcard.mdx +++ b/integrations/payments/agentcard.mdx @@ -528,3 +528,28 @@ merchant created the expected order. return `indeterminate` when the sources disagree or the merchant record is unavailable, and don't retry automatically. pass the aliases to the [browser agent payments guide](/browsers/enable-payments-in-browser-agent) and observe item events while the checkout runs. + +# bring-your-own agentcard oauth client + +the flow above uses KERNEL-managed credentials. to use your own oauth client, +register a [provider configuration](/vaults#provider-configurations) with +organization-scoped authentication. `agentcard-client.json` must contain +`client_id` and `client_secret`. keep it readable only by its owner (for example, +mode `0600`) and outside the agent's accessible files. + +```bash CLI +kernel vault-provider-configs create --name checkout-agentcard --provider agentcard \ + --credentials-file "$HOME/.config/kernel/agentcard-client.json" +``` + +unlike the KERNEL-managed wallet response, this config response exposes +`test_mode` (`true` means sandbox, `false` means live). verify that it matches +your expected mode, then reference the config when creating the wallet: + +```bash CLI +kernel vaults wallets create user-12345 agentcard-wallet --provider agentcard \ + --provider-config-name checkout-agentcard --spec '{}' --open +``` + +run `--open` only in a trusted, human-operated terminal. complete the returned +hosted enrollment action, then continue with card creation above. diff --git a/integrations/payments/stripe-link.mdx b/integrations/payments/stripe-link.mdx index aada721..95b7940 100644 --- a/integrations/payments/stripe-link.mdx +++ b/integrations/payments/stripe-link.mdx @@ -342,3 +342,37 @@ substituted, not that the processor accepted the payment or the merchant created an order. don't repeat `authorize` or create a replacement item to retry an unknown purchase. inspect item events and the merchant's order state first. + +# bring-your-own link oauth client + +prefer KERNEL's oauth client for the flow above. with your own client, your +backend must construct the human-facing authorization url, manage state and +pkce, and handle the redirect. register your backend's callback with stripe, +validate the returned state, and exchange the code using the original pkce +verifier and client credentials. keep the client secret, verifier, and tokens +out of agent context, browser code, urls, and logs. + +register a [provider configuration](/vaults#provider-configurations) with +organization-scoped authentication. `link-client.json` must contain `client_id` +and `client_secret`. keep credential and token files readable only by their +owner (for example, mode `0600`) and outside the agent's accessible files. + +```bash CLI +kernel vault-provider-configs create --name checkout-link --provider link \ + --credentials-file "$HOME/.config/kernel/link-client.json" +``` + +create the wallet using that config and the grant from your backend's token +exchange. `link-grant.json` must contain `access_token` and `refresh_token` from +the same grant, with a currently valid access token. run this from your trusted +backend or a human-operated terminal, not the agent: + +```bash CLI +kernel vaults wallets create user-12345 link-wallet --provider link \ + --provider-config-name checkout-link --spec '{}' \ + --tokens-file "$HOME/.config/kernel/link-grant.json" +``` + +successful import returns a `connected` wallet; continue with payment-method +selection. KERNEL takes over refresh-token rotation, so your backend must stop +refreshing that grant. diff --git a/vaults.mdx b/vaults.mdx index 9ca0c7c..f76b4fb 100644 --- a/vaults.mdx +++ b/vaults.mdx @@ -182,6 +182,30 @@ read the [payments overview](/integrations/payments/overview) for the shared lifecycle or use the [link by stripe](/integrations/payments/stripe-link) and [agentcard](/integrations/payments/agentcard) provider guides. +## provider configurations + +use KERNEL-managed credentials by default. if you need your own client, follow +the optional setup in [link](/integrations/payments/stripe-link#bring-your-own-link-oauth-client) +or [agentcard](/integrations/payments/agentcard#bring-your-own-agentcard-oauth-client). a named +provider configuration stores your application's `client_id` and `client_secret`, +not an end user's wallet grant. credentials are encrypted at rest; secrets are +never returned. + +configurations are organization-scoped and shared across projects, unlike +project-scoped vaults. create, update, and delete require organization-scoped +authentication; project-scoped api keys receive `403`. names are unique within +the organization, and duplicate creates return `409` without replacing secrets. + +- **selection:** choose exactly one config `id` or `name` when creating a wallet. the cli accepts `--provider-config-id` or `--provider-config-name`; responses resolve names to ids. +- **binding:** the wallet's configuration is immutable, and cards inherit it. renaming a config preserves bindings. +- **rotation:** updating `client_secret` affects all bound wallets. provider, client id, and agentcard mode cannot change; changing clients requires a new config and new wallets. +- **deletion:** returns `409` while any non-deleted item references the config, even if disconnected. it does not delete the external oauth client or revoke unrelated grants. +- **recovery:** `recovery_required` means a card's provider outcome is unresolved. it stops item wait loops and blocks new authorization, checkout, and deletion of the card or its parent wallet/vault. + +for recovery, inspect existing evidence and contact the provider or support when +manual reconciliation is needed. there is no reset operation; deletion is not +payment recovery. + ## Initial item specifications the initial release accepts these `spec` fields. fields not listed here are rejected. @@ -190,8 +214,12 @@ the initial release accepts these `spec` fields. fields not listed here are reje | provider | required fields | optional fields | | --------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -| link | `provider: 'link'`, `authorization.method: 'oauth'`, `authorization.client.type: 'kernel_managed'` | none | -| agentcard | `provider: 'agentcard'` | `user_id` for a user already enrolled through a wallet in the organization | +| link | `provider: 'link'`, `authorization.method: 'oauth'`, `authorization.client` | write-only `authorization.tokens` is required only with a customer-managed client | +| agentcard | `provider: 'agentcard'` | `provider_config`; `user_id` for a user already enrolled in the organization under the same configuration | + +the default link client is `{type: 'kernel_managed'}`. for your own client, set +`authorization.client` to `{type: 'customer_managed', provider_config: {name: 'checkout-link'}}` +and supply `authorization.tokens` with `access_token` and `refresh_token`. for payment settings ui, enforce at most one wallet per provider in each vault. the api currently enforces uniqueness by item key, not by wallet provider, so a @@ -231,8 +259,8 @@ wallet status values are: card status values are: -- link: `requested`, `pending_authorization`, `ready`, `consumed`, `expired`, `declined` -- agentcard: `requested`, `ready`, `pending_approval`, `degraded` +- link: `requested`, `pending_authorization`, `ready`, `consumed`, `expired`, `declined`, `recovery_required` +- agentcard: `requested`, `ready`, `pending_approval`, `degraded`, `recovery_required` card state can include `masks.brand`, `masks.last4`, and read-only aliases: `number`, `cvc`, `exp_month`, and `exp_year`. aliases are non-sensitive stand-ins, not standalone credentials or permission to use the provider-backed value.