@itpay/cli 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/docs/agent/buyer/cart-checkout.json +1 -1
- package/docs/agent/buyer/payment-qr.json +5 -4
- package/docs/agent/buyer/payment-wait.json +3 -2
- package/docs/agent/buyer/quickstart.json +3 -2
- package/lib/buyer.js +74 -37
- package/package.json +1 -1
- package/skills/itpay-buyer/SKILL.md +6 -1
package/README.md
CHANGED
|
@@ -239,7 +239,8 @@ Payment QR rules:
|
|
|
239
239
|
- Otherwise render the ItPay-hosted `qr_png_url` / `preferred_qr_url`.
|
|
240
240
|
- Use `mobile_wallet_url` only as a human mobile fallback.
|
|
241
241
|
- Do not generate your own QR from payment URLs.
|
|
242
|
-
- In agent app clients, send `human_visible_markdown` to the human first, then run `
|
|
242
|
+
- In agent app clients, send `human_visible_markdown` to the human first, then run `after_human_visible_markdown.command`.
|
|
243
|
+
- If status is `payment_handoff_required`, `next` is the human reply step, not payment wait.
|
|
243
244
|
- Treat only `payment_intent.verified` as payment success.
|
|
244
245
|
|
|
245
246
|
If the human wants the agent to analyze delivered content, the human must reveal
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
{
|
|
70
70
|
"intent": "do both steps through the high-level command",
|
|
71
71
|
"command": "itp buy <variant_id> --email <buyer_email> --phone <buyer_phone> --display agent --no-wait-payment --json",
|
|
72
|
-
"success_signal": "response.status is waiting_human_auth,
|
|
72
|
+
"success_signal": "response.status is waiting_human_auth, payment_handoff_required, payment_verified, or delivery_claimable"
|
|
73
73
|
}
|
|
74
74
|
],
|
|
75
75
|
"agent_rules": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
{
|
|
19
19
|
"intent": "create payment intent through the high-level buy flow",
|
|
20
20
|
"command": "itp buy <variant_id> --email <buyer_email> --phone <buyer_phone> --display agent --no-wait-payment --json",
|
|
21
|
-
"success_signal": "response.human_visible_markdown
|
|
21
|
+
"success_signal": "response.status is payment_handoff_required; response.human_visible_markdown is present; response.after_human_visible_markdown.command is the wait command to run after showing the QR/link"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"intent": "recover a scanner order-not-found display problem",
|
|
@@ -33,8 +33,9 @@
|
|
|
33
33
|
"Payment QR display requires both a valid/saved buyer session and payment_intent_id. If payment_intent_id appears before buyer_session is saved, run buyer checkout resume/status instead of showing payment QR.",
|
|
34
34
|
"Do not stop after showing auth_qr unless the human explicitly asks you to pause. Keep waiting/resuming the same checkout so the post-auth payment handoff can continue.",
|
|
35
35
|
"Do not describe auth_qr as payment success or payment proof. Only payment_intent.verified proves payment.",
|
|
36
|
-
"In Codex or Claude Code app clients, the default UX is show-then-wait: send response.human_visible_markdown to the human first, then run response.
|
|
36
|
+
"In Codex or Claude Code app clients, the default UX is show-then-wait: send response.human_visible_markdown to the human first, then run response.after_human_visible_markdown.command.",
|
|
37
37
|
"For Telegram-style message clients, show response.human_visible_markdown and stop unless the human asks you to keep waiting or returns with a payment question.",
|
|
38
|
+
"When response.status is payment_handoff_required, response.next is the human reply step, not payment wait.",
|
|
38
39
|
"MUST show local_qr_path first when present. Many agent clients do not reliably render remote QR images; local_qr_path is the most reliable desktop/chat display artifact.",
|
|
39
40
|
"If local_qr_path is not present, show qr_png_url or preferred_qr_url as the primary scannable QR. This is an ItPay-hosted human QR image; it may render the native provider payment code for scanner reliability, but the agent must not request or decode the raw provider payload.",
|
|
40
41
|
"Use qr_image_url/SVG only as a fallback when PNG/local rendering is unavailable.",
|
|
@@ -42,8 +43,8 @@
|
|
|
42
43
|
"payment_entry_url is the stable ItPay status/payment page. qr_png_url/local_qr_path is usually the better desktop scanner artifact.",
|
|
43
44
|
"The provider can briefly show order not found even after precreate succeeded. Tell the human to wait 30-60 seconds and retry the same QR/page. Do not create a new checkout, do not create a new payment intent, and do not repeatedly refresh unless the ItPay page or CLI explicitly asks for recovery.",
|
|
44
45
|
"Opening the payment page must not be treated as paid.",
|
|
45
|
-
"Do not run payment wait before the QR/link has been sent to the human.",
|
|
46
|
-
"After showing QR, run
|
|
46
|
+
"Do not run payment wait before the QR/link has been sent to the human. If you accidentally do, CLI returns payment_handoff_required instead of blocking.",
|
|
47
|
+
"After showing QR, run after_human_visible_markdown.command or buyer payment wait <payment_intent_id> --qr-shown for the same payment_intent_id."
|
|
47
48
|
],
|
|
48
49
|
"forbidden": [
|
|
49
50
|
"Do not encode payment_entry_url into a new QR yourself when qr_png_url/local_qr_path is available.",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"commands": [
|
|
18
18
|
{
|
|
19
19
|
"intent": "wait for payment verified event",
|
|
20
|
-
"command": "itp buyer payment wait <payment_intent_id> --json",
|
|
20
|
+
"command": "itp buyer payment wait <payment_intent_id> --qr-shown --json",
|
|
21
21
|
"success_signal": "response.payment_event.event_type == payment_intent.verified"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
}
|
|
28
28
|
],
|
|
29
29
|
"agent_rules": [
|
|
30
|
-
"Start payment wait only after the QR image/link has already been sent to the human.",
|
|
30
|
+
"Start payment wait only after the QR image/link has already been sent to the human; use --qr-shown to confirm that step is complete.",
|
|
31
|
+
"If you run payment wait without --qr-shown while payment is still pending, CLI returns payment_handoff_required and human_visible_markdown instead of long-polling.",
|
|
31
32
|
"Payment wait is a recovery loop around the same payment_intent_id, not a one-shot command.",
|
|
32
33
|
"wait.timeout is a heartbeat, not a payment failure.",
|
|
33
34
|
"In Codex or Claude Code app clients, after showing QR, wait online for a short visible cycle first. If the human still has not paid, explain that the same QR/link remains valid and pause for their reply.",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
{
|
|
38
38
|
"intent": "buy a selected variant with the high-level cart-first flow",
|
|
39
39
|
"command": "itp buy <variant_id> --email <buyer_email> --phone <buyer_phone> --display agent --no-wait-payment --json",
|
|
40
|
-
"success_signal": "response.status becomes waiting_human_auth or
|
|
40
|
+
"success_signal": "response.status becomes waiting_human_auth or payment_handoff_required; if payment_handoff_required, send response.human_visible_markdown to the human before running response.after_human_visible_markdown.command"
|
|
41
41
|
}
|
|
42
42
|
],
|
|
43
43
|
"agent_rules": [
|
|
@@ -54,8 +54,9 @@
|
|
|
54
54
|
"After showing auth_qr, keep running/resuming the same checkout unless the human explicitly asks you to pause. Do not stop merely because a QR was displayed.",
|
|
55
55
|
"When a buyer command returns buyer_session.status=buyer_session_saved, the CLI has stored the buyer account session for this agent device. You may continue with checkout/payment or `buyer vault` commands without asking the human for a token.",
|
|
56
56
|
"Vault grants are only for reading approved delivered artifacts. They are not buyer session credentials and do not authorize refunds or account/order management.",
|
|
57
|
-
"Use high-level itp buy when possible, but in agent app clients split payment into two visible steps: first return and show human_visible_markdown, then run
|
|
57
|
+
"Use high-level itp buy when possible, but in agent app clients split payment into two visible steps: first return and show human_visible_markdown, then run after_human_visible_markdown.command.",
|
|
58
58
|
"If response.human_visible_markdown is present, send it to the human immediately in the same user-visible message. It includes the QR image and payment link.",
|
|
59
|
+
"If response.status is payment_handoff_required, do not run payment wait from next.command; next is the human-visible reply. Only after the QR/link is visible may you run after_human_visible_markdown.command.",
|
|
59
60
|
"Show the returned payment QR exactly as provided before starting payment wait.",
|
|
60
61
|
"Payment truth comes only from payment_intent.verified.",
|
|
61
62
|
"Secure delivery goes to the human first; report redacted delivery status only."
|
package/lib/buyer.js
CHANGED
|
@@ -45,18 +45,15 @@ async function buyerBuy(flags) {
|
|
|
45
45
|
|
|
46
46
|
if (flags.no_wait || flags.no_wait_payment || showThenWait) {
|
|
47
47
|
output(buyerRunOutput({
|
|
48
|
-
status: "
|
|
48
|
+
status: "payment_handoff_required",
|
|
49
49
|
selection,
|
|
50
50
|
cart,
|
|
51
51
|
checkout,
|
|
52
52
|
payment_intent: intent,
|
|
53
53
|
payment_handoff: paymentHandoff(intent),
|
|
54
|
-
agent_next_actions:
|
|
55
|
-
next:
|
|
56
|
-
|
|
57
|
-
safe_for_agent: true,
|
|
58
|
-
instruction: "Send human_visible_markdown to the human first, then run this wait command unless the human explicitly asked you to pause."
|
|
59
|
-
}
|
|
54
|
+
agent_next_actions: paymentHandoffAgentNextActions(),
|
|
55
|
+
next: paymentHandoffNext(),
|
|
56
|
+
after_human_visible_markdown: paymentHandoffAfter(intent)
|
|
60
57
|
}));
|
|
61
58
|
return;
|
|
62
59
|
}
|
|
@@ -317,19 +314,16 @@ async function buyer(command, rest, flags) {
|
|
|
317
314
|
const intent = await getBuyerPaymentIntent(checkout.payment_intent_id, flags);
|
|
318
315
|
await renderItPayPaymentAction(intent, flags);
|
|
319
316
|
output(buyerRunOutput({
|
|
320
|
-
status: intent.status === "verified" ? "payment_verified" : "
|
|
317
|
+
status: intent.status === "verified" ? "payment_verified" : "payment_handoff_required",
|
|
321
318
|
checkout,
|
|
322
319
|
payment_intent: intent,
|
|
323
320
|
payment_handoff: intent.status === "verified" ? undefined : paymentHandoff(intent),
|
|
324
321
|
buyer_session: buyerSessionClaimStatus(claimedSession),
|
|
325
|
-
agent_next_actions: intent.agent_next_actions || checkout.agent_next_actions || ["
|
|
322
|
+
agent_next_actions: intent.status === "verified" ? (intent.agent_next_actions || checkout.agent_next_actions || ["poll_checkout"]) : paymentHandoffAgentNextActions(),
|
|
326
323
|
next: intent.status === "verified"
|
|
327
324
|
? { command: cliCommand("buyer", "checkout", "status", checkout.checkout_id, "--json"), safe_for_agent: true }
|
|
328
|
-
:
|
|
329
|
-
|
|
330
|
-
safe_for_agent: true,
|
|
331
|
-
instruction: "Send human_visible_markdown to the human first, then run this wait command unless the human explicitly asked you to pause."
|
|
332
|
-
}
|
|
325
|
+
: paymentHandoffNext(),
|
|
326
|
+
after_human_visible_markdown: intent.status === "verified" ? undefined : paymentHandoffAfter(intent)
|
|
333
327
|
}));
|
|
334
328
|
return;
|
|
335
329
|
}
|
|
@@ -343,16 +337,13 @@ async function buyer(command, rest, flags) {
|
|
|
343
337
|
const intent = await createBuyerPaymentIntent(checkout.checkout_id, flags);
|
|
344
338
|
await renderItPayPaymentAction(intent, flags);
|
|
345
339
|
output(buyerRunOutput({
|
|
346
|
-
status: "
|
|
340
|
+
status: "payment_handoff_required",
|
|
347
341
|
checkout,
|
|
348
342
|
payment_intent: intent,
|
|
349
343
|
payment_handoff: paymentHandoff(intent),
|
|
350
|
-
agent_next_actions:
|
|
351
|
-
next:
|
|
352
|
-
|
|
353
|
-
safe_for_agent: true,
|
|
354
|
-
instruction: "Send human_visible_markdown to the human first, then run this wait command unless the human explicitly asked you to pause."
|
|
355
|
-
}
|
|
344
|
+
agent_next_actions: paymentHandoffAgentNextActions(),
|
|
345
|
+
next: paymentHandoffNext(),
|
|
346
|
+
after_human_visible_markdown: paymentHandoffAfter(intent)
|
|
356
347
|
}));
|
|
357
348
|
return;
|
|
358
349
|
}
|
|
@@ -371,6 +362,19 @@ async function buyer(command, rest, flags) {
|
|
|
371
362
|
const paymentIntentID = flags.payment_intent || flags.payment_intent_id || positional(rest, 1) || readState().last_core_payment_intent_id;
|
|
372
363
|
if (!paymentIntentID) throw new Error("payment_intent_id is required");
|
|
373
364
|
const intent = await getBuyerPaymentIntent(paymentIntentID, flags);
|
|
365
|
+
if (intent.status !== "verified" && !paymentQRShown(flags)) {
|
|
366
|
+
await renderItPayPaymentAction(intent, flags);
|
|
367
|
+
output(buyerRunOutput({
|
|
368
|
+
status: "payment_handoff_required",
|
|
369
|
+
payment_intent: intent,
|
|
370
|
+
payment_handoff: paymentHandoff(intent),
|
|
371
|
+
payment_guidance: paymentRecoveryGuidance(intent, { event_type: "payment_display_required" }),
|
|
372
|
+
agent_next_actions: paymentHandoffAgentNextActions(),
|
|
373
|
+
next: paymentHandoffNext(),
|
|
374
|
+
after_human_visible_markdown: paymentHandoffAfter(intent)
|
|
375
|
+
}));
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
374
378
|
const event = intent.status === "verified"
|
|
375
379
|
? { event_type: "payment_intent.verified", payment_intent_id: paymentIntentID, agent_next_actions: intent.agent_next_actions || ["poll_checkout"] }
|
|
376
380
|
: await waitBuyerPayment(intent, flags);
|
|
@@ -382,7 +386,7 @@ async function buyer(command, rest, flags) {
|
|
|
382
386
|
agent_next_actions: event.agent_next_actions || intent.agent_next_actions || paymentAgentNextActions(intent, event),
|
|
383
387
|
next: event.event_type === "payment_intent.verified"
|
|
384
388
|
? { command: intent.checkout_id ? cliCommand("buyer", "checkout", "status", intent.checkout_id, "--json") : undefined, safe_for_agent: true }
|
|
385
|
-
: { command:
|
|
389
|
+
: { command: paymentWaitCommand(paymentIntentID, { qrShown: true }), safe_for_agent: true }
|
|
386
390
|
}));
|
|
387
391
|
return;
|
|
388
392
|
}
|
|
@@ -392,18 +396,15 @@ async function buyer(command, rest, flags) {
|
|
|
392
396
|
const refreshed = await refreshBuyerPaymentQR(paymentIntentID, flags);
|
|
393
397
|
await renderItPayPaymentAction(refreshed, flags);
|
|
394
398
|
output(buyerRunOutput({
|
|
395
|
-
status: refreshed.status === "verified" ? "payment_verified" : "
|
|
399
|
+
status: refreshed.status === "verified" ? "payment_verified" : "payment_handoff_required",
|
|
396
400
|
payment_intent: refreshed,
|
|
397
401
|
payment_handoff: refreshed.status === "verified" ? undefined : paymentHandoff(refreshed),
|
|
398
402
|
payment_guidance: paymentRecoveryGuidance(refreshed, { event_type: refreshed.status === "verified" ? "payment_intent.verified" : "qr_refreshed" }),
|
|
399
|
-
agent_next_actions: refreshed.agent_next_actions || paymentAgentNextActions(refreshed, { event_type:
|
|
403
|
+
agent_next_actions: refreshed.status === "verified" ? (refreshed.agent_next_actions || paymentAgentNextActions(refreshed, { event_type: "payment_intent.verified" })) : paymentHandoffAgentNextActions(),
|
|
400
404
|
next: refreshed.status === "verified"
|
|
401
405
|
? { command: cliCommand("buyer", "checkout", "status", refreshed.checkout_id, "--json"), safe_for_agent: true }
|
|
402
|
-
:
|
|
403
|
-
|
|
404
|
-
safe_for_agent: true,
|
|
405
|
-
instruction: "Send human_visible_markdown to the human first, then run this wait command unless the human explicitly asked you to pause."
|
|
406
|
-
}
|
|
406
|
+
: paymentHandoffNext(),
|
|
407
|
+
after_human_visible_markdown: refreshed.status === "verified" ? undefined : paymentHandoffAfter(refreshed)
|
|
407
408
|
}));
|
|
408
409
|
return;
|
|
409
410
|
}
|
|
@@ -1052,7 +1053,7 @@ function paymentHandoff(intent = {}) {
|
|
|
1052
1053
|
const preferredQRURL = action.preferred_qr_url || qrPNGURL || action.qr_image_url || intent.qr_image_url || intent.qr?.image_url || "";
|
|
1053
1054
|
const localQRPath = action.local_qr_path || intent.local_qr_path || "";
|
|
1054
1055
|
const mobileWalletURL = action.mobile_wallet_url || intent.mobile_wallet_url || "";
|
|
1055
|
-
const waitCommand = paymentWaitCommand(paymentIntentID, { short: true });
|
|
1056
|
+
const waitCommand = paymentWaitCommand(paymentIntentID, { short: true, qrShown: true });
|
|
1056
1057
|
return {
|
|
1057
1058
|
type: "payment_qr_handoff",
|
|
1058
1059
|
payment_intent_id: paymentIntentID || null,
|
|
@@ -1066,7 +1067,8 @@ function paymentHandoff(intent = {}) {
|
|
|
1066
1067
|
markdown: paymentHandoffMarkdown({ localQRPath, qrPNGURL, preferredQRURL, entryURL, mobileWalletURL }),
|
|
1067
1068
|
wait_command: waitCommand || null,
|
|
1068
1069
|
safe_for_agent: true,
|
|
1069
|
-
instruction: "Show markdown to the human first. Then run wait_command and wait for payment_intent.verified unless the human asked you to pause."
|
|
1070
|
+
instruction: "Show markdown to the human first. Then run wait_command and wait for payment_intent.verified unless the human asked you to pause.",
|
|
1071
|
+
display_targets: paymentHandoffDisplayTargets()
|
|
1070
1072
|
};
|
|
1071
1073
|
}
|
|
1072
1074
|
|
|
@@ -1080,11 +1082,46 @@ function paymentHandoffMarkdown({ localQRPath = "", qrPNGURL = "", preferredQRUR
|
|
|
1080
1082
|
return lines.join("\n\n");
|
|
1081
1083
|
}
|
|
1082
1084
|
|
|
1083
|
-
function paymentWaitCommand(paymentIntentID, { short = false } = {}) {
|
|
1085
|
+
function paymentWaitCommand(paymentIntentID, { short = false, qrShown = false } = {}) {
|
|
1084
1086
|
if (!paymentIntentID) return "";
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1087
|
+
const args = ["buyer", "payment", "wait", paymentIntentID];
|
|
1088
|
+
if (short) args.push("--timeout", "60");
|
|
1089
|
+
if (qrShown) args.push("--qr-shown");
|
|
1090
|
+
args.push("--json");
|
|
1091
|
+
return cliCommand(...args);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
function paymentQRShown(flags = {}) {
|
|
1095
|
+
if (flags.qr_shown === undefined) return false;
|
|
1096
|
+
return booleanFlag(flags.qr_shown);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
function paymentHandoffAgentNextActions() {
|
|
1100
|
+
return ["show_human_visible_markdown"];
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
function paymentHandoffNext() {
|
|
1104
|
+
return {
|
|
1105
|
+
type: "reply_to_human",
|
|
1106
|
+
safe_for_agent: false,
|
|
1107
|
+
instruction: "Send human_visible_markdown to the human now. Do not run payment wait until this message is visible to the human."
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
function paymentHandoffAfter(intent = {}) {
|
|
1112
|
+
return {
|
|
1113
|
+
command: paymentWaitCommand(intent.payment_intent_id, { short: true, qrShown: true }),
|
|
1114
|
+
safe_for_agent: true,
|
|
1115
|
+
instruction: "Run this only after human_visible_markdown has been sent to the human."
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
function paymentHandoffDisplayTargets() {
|
|
1120
|
+
return {
|
|
1121
|
+
desktop_app: ["local_qr_path", "qr_png_url", "payment_entry_url"],
|
|
1122
|
+
terminal: ["qr_png_url", "payment_entry_url", "mobile_wallet_url"],
|
|
1123
|
+
chat_cloud: ["qr_png_url", "payment_entry_url", "mobile_wallet_url"]
|
|
1124
|
+
};
|
|
1088
1125
|
}
|
|
1089
1126
|
|
|
1090
1127
|
function paymentRecoveryGuidance(intent = {}, event = {}) {
|
|
@@ -1426,7 +1463,7 @@ async function waitBuyerPayment(intent, flags = {}) {
|
|
|
1426
1463
|
action: intent?.human_action || null,
|
|
1427
1464
|
lastHeartbeatAt,
|
|
1428
1465
|
flags,
|
|
1429
|
-
command:
|
|
1466
|
+
command: paymentWaitCommand(paymentIntentID, { qrShown: true })
|
|
1430
1467
|
});
|
|
1431
1468
|
}
|
|
1432
1469
|
return lastEvent || { event_type: "wait.timeout", payment_intent_id: paymentIntentID, cursor, agent_next_actions: ["wait_payment"] };
|
|
@@ -1651,7 +1688,7 @@ function buyerDocsFor(value = {}) {
|
|
|
1651
1688
|
topics.add("cart-checkout");
|
|
1652
1689
|
topics.add("payment-qr");
|
|
1653
1690
|
}
|
|
1654
|
-
if (status.includes("waiting_user_payment") || actions.includes("wait_payment") || value.payment_intent?.human_action || value.payment_intent?.qr_image_url) {
|
|
1691
|
+
if (status.includes("payment_handoff") || status.includes("waiting_user_payment") || actions.includes("show_human_visible_markdown") || actions.includes("wait_payment") || value.payment_intent?.human_action || value.payment_intent?.qr_image_url) {
|
|
1655
1692
|
topics.add("payment-qr");
|
|
1656
1693
|
topics.add("payment-wait");
|
|
1657
1694
|
}
|
package/package.json
CHANGED
|
@@ -213,10 +213,15 @@ This keeps JSON output machine-readable while allowing the CLI to prepare a
|
|
|
213
213
|
local QR image path for clients that cannot render remote SVG reliably. In
|
|
214
214
|
Codex or Claude Code app clients, prefer `--no-wait-payment`: send
|
|
215
215
|
`human_visible_markdown` to the human first, then run
|
|
216
|
-
`
|
|
216
|
+
`after_human_visible_markdown.command`. If the human is on mobile, present
|
|
217
217
|
`mobile_wallet_url` as a clickable human-only fallback; do not convert it into a
|
|
218
218
|
QR.
|
|
219
219
|
|
|
220
|
+
If a response has `status=payment_handoff_required`, `next` is the user-visible
|
|
221
|
+
reply step, not payment wait. Do not run `buyer payment wait` until the QR/link
|
|
222
|
+
has been sent to the human; then use the returned
|
|
223
|
+
`after_human_visible_markdown.command` with `--qr-shown`.
|
|
224
|
+
|
|
220
225
|
For first-purchase auth, treat the returned ItPay authorization entry as a
|
|
221
226
|
single human orchestration entry. It may open Alipay login/registration first
|
|
222
227
|
and then payment after ItPay receives the OAuth callback. Do not call
|