@nuanu-ai/magicpay-cli
v0.1.35
Published
MagicPay workflow CLI for Memory-backed browser field fill and approvals
Maintainers
Readme
@nuanu-ai/magicpay-cli
Safely fill login, identity, checkout, donation, subscription, and payment pages from MagicPay Memory.
MagicPay CLI handles the Memory fill part of a browser session. It uses the
active MagicBrowse browser session to observe visible field targets, fetches
value-free Memory item descriptors from MagicPay, lets the Memory matcher
choose semantic matches, plans the fill by fieldRef, and applies the plan
without exposing raw values to the agent driving it.
The current product fill path is Memory target matching plus plan-fill /
apply-fill.
Use it together with any browser-automation tool (for example
@nuanu-ai/magicbrowse-cli) that opens the page and attaches to the
browser over the Chrome DevTools Protocol (CDP).
Mental Model
These terms appear throughout this README:
<cdp-url>— WebSocket URL of an already running Chrome session, produced by whatever tool opened the browser.- Memory item descriptor — a value-free field description from MagicPay
Memory. Public item projections contain stable refs and safe semantic facts,
but no materialization capability. Only an authorized catalog entry carries
the separate, scoped
valueHandleneeded to materialize a value. fieldRef— the stable, value-free logical Memory field identity chosen by the matcher. Provider-account refs use<accountId>:<fieldKey>and pool-card refs usepayment_card_pool:<fieldKey>. AfieldRefnever grants value access; the separatevalueHandleis the short-lived capability.plan-fill— observes the current browser page, fetches value-free Memory descriptors, runs the Memory matcher, builds a value-free fill plan, and stores the latest short-lived plan in the active workflow.payment_card.authorization_required— aplan-fillblocker/warning that means MagicPay Memory has a provider-backed payment card, but card handles are hidden until payment authorization is approved for the active workflow session.provider_needs_reauth— an approved provider-card reservation is expired, inactive, or no longer present. Its blocker carries the exact safe reason andreservationExpiresAt; create a freshauthorize-paymentapproval and rerunplan-fill. MagicPay does not renew or reuse it automatically.apply-fill— refreshes the browser snapshot, materializes only the approved values needed for the active plan, writes them into the browser through MagicBrowse, and stops before final commitment actions such as Pay, Book, Send, or Submit.fill-field— lower-automation recovery for one missed or wrongly targeted field. The public CLI accepts an observed target id such as--target 1and resolves it internally to the current browser target ref.fieldRefis an exact value-free identity: a stale ref returnsinvalid_memory_field_refwith safe current refs and tells the caller to rerunplan-fill.currentRequestId— the pending runtime request saved by a typed action command with--return-pending, then reused byconfirm-otpandwait-request.- protected values — secrets the user must approve each time (passwords, card numbers, identity documents). Released only through Memory value materialization after the fill plan is approved or through a typed action command on a live MagicPay workflow.
Install
npm i -g @nuanu-ai/magicpay-cli@latestThe supported production setup is one global magicpay installation selected
first on PATH. The CLI does not copy or synchronize packages between npm
prefixes. If multiple binaries may be present, run magicpay doctor before
changing an installation.
API Setup
Configure the API key once:
Get an account and API key at https://app.magiccard.ai/signup.
magicpay init <magicpay-api-key>
magicpay statusThe CLI uses its bundled default MagicPay gateway URL for normal setup. No URL parameter is needed unless you intentionally target another environment.
magicpay status is the normal readiness check before a secure form fill.
Use magicpay doctor when init or status still fail. It reports the invoked
executable, package root, CLI/runtime artifact build ID, PATH shadowing,
dependency resolution, and the backend deployment/catalog capability contract.
Missing-runtime commands defer to doctor; they do not automatically recommend
replacing a source, linked, package-local, ambiguous, equal, or local-ahead
build with registry @latest.
Doctor is read-only: it does not persist update-check state or modify an npm
prefix. Any update hint is scoped to the verified, non-linked global prefix
that owns the first magicpay executable on PATH. npm does not retain a
portable registry-origin attestation for installed files, so this proves
prefix ownership and semver comparability, not that the bytes came from npm;
the artifact build ID remains the authoritative byte identity.
On Windows, shell-specific command precedence cannot always be recovered from
the Node process launched by an npm shim. If doctor reports
windows_shell_unresolved, run it with MAGICPAY_WINDOWS_SHELL set to
native, powershell, or posix for the shell that launched magicpay. This
only selects the read-only PATH ordering policy; it does not modify the install.
To point the CLI at a non-default MagicPay environment (staging, self-host, test), persist the API origin:
magicpay init <magicpay-api-key> --api-url https://your-magicpay-endpoint/functions/v1/apiThe URL is persisted into the active MagicPay home config alongside the key:
~/.magicpay/config.json by default, or $MAGICPAY_HOME/config.json when
MAGICPAY_HOME is set.
Named environments
When you work against more than one backend (production plus a dev or local stack), register each one as a named environment so switching never requires re-entering keys or URLs:
# Register environments (setup verify and init both accept --env)
magicpay setup start --email [email protected] --env development --api-url https://your-dev-project.supabase.co/functions/v1/api
magicpay init <prod-api-key> --env production --api-url https://api.magicpay.nuanu.ai/functions/v1/api
magicpay setup start --email [email protected] --env local --api-url https://your-feature-project.supabase.co/functions/v1/api
# Switch with one command; every CLI in the MagicPay family follows
magicpay env use development
magicpay env listEach environment stores its own API key and API URL. The active environment is
used by magicpay, magicbrowse, and magicsearch alike, and all three
resolve per-session state lanes the same way: --session <id> >
MAGICPAY_SESSION > the only live session > legacy singleton state (the
shared resolver lives in @nuanu-ai/magicpay-home). Resolution order
for every command: explicit flags → MAGICPAY_API_URL /
MAGICPAY_API_KEY / MAGICPAY_ENV
environment variables → the active named
environment → the legacy single gateway config block → the bundled
production default. Selecting an environment name that is not defined fails
loudly instead of silently falling back to another backend.
Hosted top-up, Memory request, choice, and approval links always print the
production web origin (https://app.magiccard.ai), regardless of the active
environment; swap the domain by hand when testing against localhost or
staging. --hosted-base-url on an individual link-emitting command remains an
explicit one-shot diagnostic override.
Workflow
magicpay statusmagicpay start-session [name]magicpay launch [url]ormagicpay attach <cdp-url>when a browser child is needed inside the active product workflowmagicpay solve-captcha [--timeout <s>]only when a real CAPTCHA is confirmed on the current page- Run
magicpay plan-fillfor the current page. The command observes the browser, loads value-free Memory descriptors, runs the matcher, and stores the latest plan. If the result includespayment_card.authorization_required, the Memory store has a provider-backed payment card but MagicPay cannot reveal card handles untilauthorize-paymentis approved in this session. - Run
magicpay apply-fill. The command refreshes the browser snapshot, materializes Memory handles inside MagicPay, fills through MagicBrowse primitives, and stops before final commitments. If it returnsmemory.choose_candidate, ask the user which displayed Memory candidate to use, then runmagicpay choose-memory --choice <choiceId>. If materialization returnsrequiresFreshApproval: true, branch on the exactreason, run a freshauthorize-payment, then rerunplan-fill. - For protected actions, use the typed command that matches the action:
magicpay authorize-payment ...,magicpay sign-message ..., ormagicpay confirm-action ... - For non-blocking approval handoff, add
--return-pendingto the typed action command, share itsrequestUrl, and immediately run its exactpollCommand. If an eligible payment handoff returnsconfirmOtpCommand, the user may approve with the link or provide the emailed OTP; after OTP confirmation, continue the same poll. - Continue the browser task with the browser owner. Final commitment buttons are separate orchestrator decisions, not part of Memory field fill.
magicpay end-sessionwhen the product workflow is complete
One Request Loop
Every action, choice, and protected Memory request uses the SDK's shared
follow_request poller: three-second polls, safe 15-second heartbeats,
continued waiting through approved/executing, 90 seconds of observation
grace after server expiry, and a 35-minute client safety ceiling.
share link -> start poll now -> keep the same process ->
pending/interrupted means poll the same request again ->
lost output means recover once with magicpay requests ->
request safety bound means reconcile once and report if still overdue ->
stop on server terminal, finalized-payment ready, session stop, or cancellationwait-request observes then claims fulfilled actions and choices.
wait-memory stops at fulfilled without claiming and returns the
apply-fill resume command. Diagnostic timeout, caller abort, and host
interruption preserve the same handoff; they are not denial. Server-deadline
overrun or the client safety deadline permits one magicpay requests
reconciliation, never a replacement request. Browser action deadlines end
before standalone request polling begins and do not bound the request.
Flag details:
--timeout <s>sets how longsolve-captchawaits for confirmed challenges on the current browser child.--planner-hint <text>passes a short human-readable hint about the current form toplan-fill. It must not contain page targets,targetMatches, Memory catalogs, materializers, browser writers, or raw Memory values.apply-fill --plan <planId>applies a specific stored fill plan instead of the latest active plan.choose-memory --choice <choiceId>submits a backend-owned Memory candidate choice id returned byapply-fill, then continues applying the fill plan.--return-pendingmakes a typed action command return after creating the pending request instead of blocking for the result. Auto-approved responses and post-approvalconfirm-otp/wait-requestresults includereservationExpiresAtwhen a provider-card reservation exists; the request deadline remains separate.confirm-otp --otp <digits>confirms an OTP-eligible active pending request.--session <id>and--request <id>can recover an explicit request. A successful provider-card confirmation preservesreservationExpiresAt.wait-requestresumes waiting for the active pending action or choice. It also accepts--session <id>,--request <id>,--timeout-ms <ms>, and--interval-ms <ms>; timing overrides are diagnostics, not new defaults.wait-memoryobserves a protected Memory request without claiming it. It accepts the same selectors and diagnostic timing overrides plus--plan <planId>for its protected resume command.fill-field --field-ref <fieldRef> --target <target> [--item-ref <itemRef> | --item-id <id>] [--projection-part <part>] [--hosted-base-url <url>]fills one explicit Memory field into one observed browser target as a recovery step afterplan-fill/apply-fillmissed or mis-targeted a visible field.--targetaccepts both1andselector:1; prefer the bare id copied from the current browser observation. The command never interpretsfieldRefas a name or sends it through the semantic matcher. If the selected field has a newer unsupported value type, it returnsmemory_catalog_incompatiblebefore materialization or browser writes. Hosted approval links always print the production web origin;--hosted-base-urlis an explicit one-command diagnostic override.list-memory-items,get-memory-item,delete-memory-item,create-memory-item,add-memory-field,update-memory-field, anddelete-memory-fieldare UX-first wrappers over the SDK Memory item APIs. Raw item JSON is available only through--raw-item-jsonfor service/debug use.
Example:
magicpay start-session "Checkout"
magicpay attach <cdp-url>
magicpay plan-fill
magicpay apply-fillThe workflow is:
plan-fillobserves page targets and runs the Memory matcher over value-free descriptors;plan-fillreturns a handles-only fill plan;- if a provider-backed card exists but needs payment authorization,
plan-fillreturns the non-blocking blockerpayment_card.authorization_requiredand a diagnostic warning instead of card handles; - if a prior reservation is unusable,
plan-fillreturns a blockingprovider_needs_reauthentry with an exact reason such asexpired,inactive, ornot_found, plus its safe expiry when known; apply-fillfresh-observes, materializes approved values and writes only the planned fields through MagicBrowse, then stops;- if a visible field remains empty because the matcher missed it or chose the
wrong element,
fill-fieldcan bind onefieldRefto one observed target id without exposing raw values; a stale ref fails with safe current refs instead of opening aprovide_missingrequest; - the browser owner continues from the filled state;
- typed action approvals cover the matching final action. After successful
authorize-payment, do not ask again before the approved payment submit unless amount, currency, recipient, or recurring facts changed.
Typed Action Commands
Use typed action commands when the next browser or wallet step is consequential and needs MagicPay approval:
magicpay authorize-payment --amount <number> --currency <code> --recipient <name> [--description <text>] [--recurring <true|false>] [--authorization-ref <ref>] [--item-ref <itemRef>] [--return-pending]approves one payment. Collect the final visible amount, currency, merchant/payee recipient, optional description, and optional recurring status first. After approval, proceed with the matching payment form fill and final Pay/Submit action. Stop and ask again only if amount, currency, recipient, or recurring status changed. Ifplan-fillpreviously returnedpayment_card.authorization_required, rerunplan-fillafter approval so the active session can receive the provider-backed card handles.magicpay sign-message --item-ref <walletItemId> --message <text> [--return-pending]approves signing that exact wallet message with the selected wallet item. Stop and ask again if the message changes.magicpay confirm-action --summary <text> [--details <text>] [--return-pending]approves a non-payment consequential action that has no more specific typed command. Use a short visible summary, and add details when the page context or consequences need to be explicit.
Typed approvals are exact. They do not authorize changed facts, broader future actions, or unrelated page steps.
Memory Item Commands
Use Memory item commands when the runtime needs to manage saved reusable Memory records directly. These commands return JSON on stdout like the rest of the CLI.
A Memory item is a user-owned reusable data record, not a single field. The
item label names the record that future agents and users will recognize, while
fields hold the reusable facts inside that record. Choose short labels that
describe the purpose of the group, such as Airline login, Traveler profile,
Home shipping address, Wallet, or Facts about user. Do not include raw
values in labels, do not use one field label as the item label when the item
contains a broader record, and do not create one item per field unless the user
is saving one truly standalone fact.
magicpay list-memory-items --url https://airline.example/login --status active
magicpay list-memory-items --all-sites
magicpay get-memory-item --item-id mem_airline_login
magicpay delete-memory-item --item-id mem_airline_login
magicpay create-memory-item \
--item-label "Airline login" \
--site airline.example \
--text "Login [email protected]" \
--secret-text "Password=correct-horse"
magicpay create-memory-item \
--item-label "Traveler profile" \
--person "Full name=Ada Lovelace" \
--date "Date of birth=1815-12-10" \
--phone "Phone=+14155550100" \
--secret-phone "Backup phone=+14155550101"
magicpay add-memory-field \
--item-id mem_airline_login \
--label "Recovery code" \
--value "123456" \
--secret true \
--hint "One-time recovery code"
magicpay update-memory-field \
--field-ref field_login_email \
--value [email protected]
magicpay update-memory-field \
--field-ref field_phone \
--type text
magicpay update-memory-field \
--field-ref field_password \
--label "Account password" \
--secret true \
--hint "Account password"
magicpay delete-memory-field --field-ref field_recovery_codelist-memory-items and get-memory-item return item ids, labels, statuses,
read-only markers, and field refs with labels/hints, never raw values.
Provider-backed cards can appear as readOnly: true; they are available for
fill but cannot be updated through Memory CRUD. Use --url <current-url> for
ordinary site-scoped lookup; use --all-sites only for explicit global Memory
review or editing.
On create, fields are new, so --text, --date, --phone, --person, and
their --secret-* variants use "Label=value". Existing fields are never
addressed by label. List or get the item first, select the intended fieldRef,
then use update-memory-field --field-ref <fieldRef> or
delete-memory-field --field-ref <fieldRef>.
add-memory-field and update-memory-field accept --type
text|date|phone_number|person_name. text clears semantic value type. Use
date with canonical YYYY-MM-DD, phone_number with E.164 such as
+14155550100, and person_name with a non-empty full name string. Internal
card value types such as payment_card_number and payment_card_expiry are
provider-backed only and are rejected by public Memory item commands.
--secret true|false is mutable display/logging metadata for any field. It is
not a value type and is not an encryption mode.
For chat-provided reusable facts, the expected flow is: list Memory items, find
a suitable editable item by label, scope, fields, and hints, then update fields
by fieldRef. Create a new item only when no semantically suitable item
exists. Use Facts about user only for global profile facts with no narrower
record; use a narrower label for site/account-specific logins, traveler
profiles, addresses, wallets, payment-related records, and other coherent
groups. Field labels should be short human text. Hints should help a future
agent understand when to use a field, for example Login email or username or
Passport expiry date in YYYY-MM-DD; do not put raw values or generic text like
value in hints.
create-memory-item --raw-item-json and update-memory-item --raw-item-json
exist only as service/debug escape hatches for lower-level SDK payloads. Do not
teach them as the main Memory UX.
Pending Approval And OTP
OTP is optional. A pending approval request can be completed in MagicPay web, MagicPay mobile, or by OTP when the request is eligible and the user chooses to provide the OTP they received.
magicpay authorize-payment --amount 5 --currency USD --recipient "Example merchant" --return-pending
# User approves with requestUrl, or sends the OTP only when the handoff advertises it:
magicpay confirm-otp --otp <digits>
magicpay wait-request --session <sessionId> --request <requestId>If the user approves in MagicPay UI, skip confirm-otp and still run
the same pollCommand. OTP confirmation is not success; continue the same
poll. Do not invite OTP unless requestHandoff.approvalChannels includes
otp and confirmOtpCommand is present. Never log, store, repeat, or summarize
OTP digits.
Session Lifecycle
A MagicPay task uses one workflow session that covers everything between
start-session and end-session. Three things to know:
- State lives on disk, one lane per session.
start-sessionallocates~/.magicpay/sessions/<sessionId>/(or under$MAGICPAY_HOME) holding that session'sworkflow-state.json,browser-session.json, and default browser profile. Commands read and update the lane, so you can run them as separate processes. Credentials inconfig.jsonstay shared at the home root. For the full layout, see@nuanu-ai/magicpay-home. - Parallel sessions need no setup. With one live session, every command
finds it automatically. With several, session-scoped commands require a
selector: pass
--session <sessionId>(theintentSessionIdfromstart-sessionoutput) to any of them, or exportMAGICPAY_SESSIONonce per task. Ambiguity is an error listing the live sessions, never a silent guess. Each parallel session gets its own browser and Chrome profile; the shared MagicCard balance, spend limits, and per-merchant throttling still apply across all of them, so serialize final payment authorizations. - Always finish with
end-session. It marks the session complete on the server. Usemagicpay end-session --cancelinstead when the user explicitly cancels or a hung approval blocks cleanup during cancellation; this sends a canceled terminal status and cancels unresolved workflow requests. If you forget, the session is eventually cleaned up by its server-side TTL. A laterstart-sessionnow attempts to cancel or clear the previous workflow binding before creating a new one, but manual recovery can still be needed if the remote state cannot be finalized. - Merchant success is not provider settlement. After a fresh result-page
observation confirms the merchant accepted a payment, pass
--payment-outcome merchant_confirmedand the separately observed--payment-provider-status unknown|pending|successtogether with the final amount, currency, and merchant. This can complete the workflow while the provider transaction remains pending. Useprovider_confirmedonly with an actual provider-backedsuccessobservation. - Recovery. If a CLI process is killed mid-flow, the state file is
still there. Start with
magicpay status, then usemagicpay end-sessionor a freshstart-session, followed bylaunchorattachon the approved browser when browser-dependent work resumes. Re-observe the page and rebuild Memory target matches after any meaningful page change; do not reuse a fill plan from a stale page fingerprint.
A session can end without an artifact when the user denies, the request
expires, or the session is stopped server-side. Those cases surface as
{ success: false, reason: 'denied' | 'expired' | 'canceled' | ... } —
see the JSON Output And Exit Codes section.
JSON Output And Exit Codes
Every command returns a single JSON object on stdout and exits with a status code:
- Success: JSON includes
{ "success": true, ... }, exit code0. - Failure: JSON includes
{ "success": false, "error": "<message>", ... }, exit code1. - Fatal error before the command could run: a single line written to
stderr in the form
[magicpay] Fatal: <message>, exit code1.
Example failure after an approval was denied:
{
"success": false,
"action": "apply-fill",
"error": "REQUEST_DENIED",
"reason": "denied",
"message": "The user denied this request."
}Check success first, then outcomeType, then branch on reason (for
request-level failures such as denied, expired, failed, canceled,
timeout) or on the command-specific error code.
plan-fill may also return non-fatal blockers and
diagnostics.warnings. For provider-backed cards, branch on
kind: "payment_card.authorization_required" and
status: "authorization_required"; the warning text is for display only.
For an already approved provider card that is no longer usable, branch on
kind: "provider_needs_reauth" and its exact reason instead. A failed
apply-fill / fill-field materialization preserves that reason. Reasons that
require reauthorization return nextAction: "authorize-payment" plus
requiresFreshApproval: true; provider_unavailable preserves its provider
reason without claiming that a fresh approval will fix it. Neither response
prints the capability handle.
Operating Rules
- Use
magicpay statusbefore a new MagicPay task, then start the product workflow withmagicpay start-session. - Use
magicpay launchormagicpay attachonly afterstart-session, when MagicPay needs a browser child inside the active product workflow. Re-attaching the same endpoint is allowed but is not required as a ritual. - Re-observe the page and rebuild the Memory fill plan after meaningful page changes.
- Treat post-fill browser continuation as browser-owner work. MagicPay does not click final commitment controls as part of field fill.
- Treat
payment_card.authorization_requiredas a card-present state, not as a prompt to collect raw card values. Useauthorize-paymentwhen the current payment needs that card, then re-plan. - Treat provider-card
expired,inactive,wrong_session,wrong_reservation, andnot_foundas fail-closed states. Obtain a fresh approval explicitly; never infer that an old authorization was renewed. - Before a consequential action, get the matching typed MagicPay approval:
authorize-payment,sign-message, orconfirm-action. - After typed approval, proceed with exactly that action; stop only if page facts changed.
- Treat approval as channel-neutral when the handoff advertises both MagicPay UI and OTP: either channel resolves the same pending request. OTP is never mandatory and must not be offered for link-only requests.
- Do not print, log, summarize, or persist OTP values.
- Development-only approval mocks are not production approval flows.
Command Groups
- Setup and diagnostics:
init,status,doctor - Session control:
start-session,launch/attach,end-session - CAPTCHA recovery:
solve-captcha - Memory fill:
plan-fill,apply-fill - Memory items:
list-memory-items,get-memory-item,delete-memory-item,create-memory-item,add-memory-field,update-memory-field,delete-memory-field - Secure actions:
authorize-payment,sign-message,confirm-action,confirm-otp,wait-request
Companion Tools
- You only need browser launch, attach, observe, or act:
use
@nuanu-ai/magicbrowse-cli - You need browser work and protected fills in one flow:
use
@nuanu-ai/magicbrowse-clifor browser control and@nuanu-ai/magicpay-clifor sensitive steps.
