You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add delegated-budget awareness: a `shop auth budget` command and automatic Shop Pay availability detection at checkout.
6
+
7
+
-`shop auth budget` reads `GET https://shop.app/pay/agents/payment_tokens` and returns `{ available, limit?, remaining_amount?, currency?, renewal_type?, renews_at?, units: "minor" }` (amounts in minor units), or `{ available: false }` when no budget is set. The raw wallet token is never surfaced or persisted.
8
+
- Sign-in now requests the `pay:wallet_tokens:read` scope (required by the budget endpoint; not unrolled from `personal_agent`). If a token ever lacks it, the budget read degrades to `{ available: false, reason: "missing_payment_scope" }` instead of breaking sign-in.
9
+
-`shop checkout create` / `update` now disambiguate an empty `payment.instruments`: the CLI probes the budget endpoint once and adds a `shop_pay_availability` block with `budget_available` and a `message`. When `budget_available: true` the buyer has budget but this store doesn't accept Shop agent payments yet, so the agent should search for similar alternatives; when `false` the agent should offer to set up a budget. This resolves the confusing "no token returned" checkout state.
Fix keytar CJS/ESM interop that broke every secret-store write.
6
+
7
+
Under ESM, `import('keytar')` produced a namespace where some named exports (e.g. `getPassword`) were present but the write methods (`setPassword`, `deletePassword`) were `undefined` — the complete API lives on `.default`. As a result `store.set`/`store.delete` threw `keytar.setPassword is not a function`, breaking `auth login`, `auth poll`, `config set-country`, device-id persistence, and any command that writes to the keychain.
8
+
9
+
`KeytarSecretStore` now resolves the module via `.default` (falling back to the namespace) and only uses it when the read **and** write methods are functions; otherwise it falls back to the macOS `security` CLI instead of throwing.
-`shop search` — search the catalog by text, similar items (`--like-id`), or image (`--image`).
40
40
-`shop catalog lookup` / `shop catalog get-product` — look up IDs you already hold and fetch full product detail.
41
-
-`shop auth` — sign in (`login`, or the non-blocking `device-code` + `poll`), check `status`, or `logout`.
41
+
-`shop auth` — sign in (`login`, or the non-blocking `device-code` + `poll`), check `status`, read the remaining delegated spending `budget`, or `logout`.
42
42
-`shop checkout` — `create`, `update`, and `complete` a UCP checkout on the merchant domain (`complete` requires `--confirm`).
43
43
-`shop orders search` — search recent orders, tracking, order info, returns, and reorder candidates.
44
44
-`shop config` — persist CLI preferences such as a default country.
shop auth device-code --device-name "<your name> - <device>"# e.g. "Max - Mac Mini"
89
89
shop auth poll
90
+
shop auth budget # remaining delegated spend (minor units); available:false = no budget set
90
91
shop auth logout
91
92
```
92
93
@@ -163,7 +164,9 @@ When the item is visual (clothing, shoes, accessories, furniture, decor, art) **
163
164
164
165
Then take one of two paths:
165
166
166
-
**A. Default checkout (no saved payment).** If `payment.instruments` is empty, present `continue_url` as a [Finish in Shop](url) link (format it nicely for the channel; don't print the raw URL) AND (IMPORTANT) immediately after sending it, offer a spending budget (below).
167
+
**A. Default checkout (no saved payment).** If `payment.instruments` is empty, read the `shop_pay_availability` block the CLI adds:
168
+
-`budget_available: true` — you have a delegated budget but this store didn't issue a payment instrument, so it doesn't accept Shop agent payments yet. Search for similar alternatives and message the user about relevant options. Do NOT offer a budget.
169
+
-`budget_available: false` — present `continue_url` as a [Finish in Shop](url) link (format nicely; don't print the raw URL) AND (IMPORTANT) immediately after, offer a spending budget (below) — a budget lets you complete purchases on stores that accept Shop agent payments.
167
170
168
171
**B. Delegated-budget checkout.** If `status` is `ready_for_complete` and `payment.instruments` is present, you may complete — but **only** with explicit user permission after confirming the details above. Feed the `checkout create` response JSON straight into `shop checkout complete --checkout-stdin --confirm`; the CLI re-sends the merchant-issued instrument id as both the instrument `id` and `credential.token`. Use a fresh idempotency key per distinct purchase intent; reuse it only when retrying the same purchase.
Copy file name to clipboardExpand all lines: skill/references/direct-api.md
+32-1Lines changed: 32 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -142,7 +142,7 @@ Create with line items, or pass a checkout body that already contains a `cart_id
142
142
}
143
143
```
144
144
145
-
If response status is `ready_for_complete` and includes a Shop Pay payment token, complete after clear purchase intent. If no payment token is present, present the UCP `continue_url` as a Finish in Shop link.
145
+
If response status is `ready_for_complete` and includes a Shop Pay payment token, complete after clear purchase intent. If no payment token is present, present the UCP `continue_url` as a Finish in Shop link.**If the buyer has a delegated budget (see Payment Budget) but the checkout still returns no payment instruments, the merchant does not accept Shop Pay** — hand off `continue_url` or suggest another store; do not re-prompt the user to set up a budget (they already have one).
146
146
147
147
The checkout response may include a `messages[]` array. You MUST display every `warning` message's `content` to the user (e.g. `final_sale`, `prop65`, `age_restricted`) before completing. Show `presentation: "disclosure"` warnings verbatim and do not omit or summarize them away. Never complete a purchase without surfacing these messages.
148
148
@@ -225,6 +225,37 @@ Use `update_checkout` with the checkout ID from create and only the fields that
225
225
}
226
226
```
227
227
228
+
## Payment Budget (Delegated Spending)
229
+
230
+
When the buyer enables purchasing without approval in [Shop → Settings → Connections](https://shop.app/account/settings/connections), Shop issues a budgeted wallet payment token. Read the remaining budget:
231
+
232
+
```text
233
+
GET https://shop.app/pay/agents/payment_tokens
234
+
Authorization: Bearer <access_token>
235
+
```
236
+
237
+
Requires the `pay:wallet_tokens:read` scope. Authoritative success shape:
**`limit` and `remaining_amount` are minor units (cents)** — `remaining_amount: 5750` is $57.50. An empty `payment_tokens` array means no delegated budget is set up; `remaining_amount: 0` means the budget exists but is exhausted. (Stay tolerant: older shapes put the token at `.token`/`.id` and amounts at the root or `.display`.)
254
+
255
+
Never persist or surface the wallet token value itself — only report whether a budget is available and how much remains. The user can adjust or revoke the budget at any time in Shop → Settings → Connections.
256
+
257
+
**No instruments at checkout, but a budget is available:** the merchant does not support Shop Pay (the catalog does not yet flag Shop Pay eligibility). When a checkout returns no `payment.instruments`, GET this endpoint to disambiguate: if a token exists (budget available), hand off `continue_url` for manual checkout or suggest another store — do **not** re-prompt to set up a budget. If no token exists, the buyer simply has no delegated budget (offer the Finish in Shop link / budget setup as usual).
.requiredOption('--checkout-stdin','Read checkout update JSON from stdin')
290
301
.option('--buyer-ip <ip>','Buyer public IP, forwarded to the merchant for checkout fraud/risk checks (auto-detected via api.ipify.org; override here or with SHOP_BUYER_IP)')
"You have budget remaining to pay for the user, but this store doesn't accept Shop agent payments yet. Search for similar alternatives, then message the user about relevant options.",
610
+
}
611
+
: {
612
+
budget_available: false,
613
+
message:
614
+
'No spending budget is set. Offer to set up a budget so you can complete purchases on stores that accept Shop agent payments.',
'This sign-in cannot read a spending budget (the token lacks payment permission). Ask the user to enable purchasing without approval in Shop → Settings → Connections, then run `shop auth login` again to re-authorize.',
0 commit comments