04-tooling

mpp tempo integration proposal

Thu Apr 30 2026 20:00:00 GMT-0400 (Eastern Daylight Time) ·tooling ·status: proposal ·⚠ high
mpptempostripe-agentic-commercel5-trajectoryagent-paymentslink-wallet-comparisonray-operating-budget

MPP + Tempo Integration Proposal — Ray Data Co

Founder’s questions (2026-05-01 15:50 ET)

  1. Do we need to setup a Tempo stable coin wallet?
  2. What is the Machine Payment Protocol (MPP)?
  3. How do we allow purchases with this pattern?
  4. Link or the Tempo MPP process shown?

What MPP is

Machine Payments Protocol (MPP) is an open IETF-track HTTP authentication scheme — co-authored by Stripe and Tempo, with contributions from Visa — that standardizes machine-to-machine payments on top of HTTP 402. The flow is three steps: client requests a resource; server returns 402 Payment Required with a WWW-Authenticate: Payment challenge; client pays (signs a Tempo tx, uses an SPT, swipes a card via Lightning, etc.) and re-requests with Authorization: Payment <credential>; server returns the resource plus a Payment-Receipt header. (spec, Stripe docs)

Critical property: payment-method agnostic. A single MPP endpoint can accept stablecoins on Tempo, USDC bridged from other chains, cards via Stripe SPTs, Lightning BTC, Solana SPL tokens, Monad ERC-20, or Stellar SEP-41 — the buyer chooses. The server doesn’t have to support each rail individually; it accepts a credential and verifies it.

Open-source spec lives at tempoxyz/mpp-specs. Official SDKs in TypeScript, Python, Rust, Go, Ruby (tempoxyz/mpp-rs, solana-foundation/mpp-sdk), plus framework middleware for Hono/Express/Next.js/Elysia. Cloudflare Workers has first-party MPP middleware (CF docs) — directly relevant to our stack.

What’s GA today (2026-05-01): The protocol spec is live. Tempo mainnet launched 2026-03-18. SDKs are published. Stripe’s MPP via PaymentIntents is in early access / waitlist (Stripe agentic commerce suite blog). The buyer-side link-cli already supports MPP via link-cli mpp pay <url>we have it installed already as of 2026-04-29.

What Tempo is

Tempo is a purpose-built Layer 1 blockchain for stablecoin payments (tempo.xyz, docs.tempo.xyz). Built on Reth SDK + Simplex Consensus. ~0.6s sub-second finality, ~100k TPS target, gas paid in USD stablecoins (no native token required). Co-incubated by Stripe and Paradigm; raised $500M at $5B valuation; design input from OpenAI, Visa, Mastercard, Shopify, UBS, Deutsche Bank, Nubank, Revolut. Visa runs an anchor validator.

Wallet model: Domain-bound passkey accounts (WebAuthn) and embeddable universal-wallet dialogs. Self-custody capable; no KYC mentioned in docs for wallet creation. USD on-ramp is via bridges (LayerZero/Stargate, Relay) — Tempo is not a USD-bank-ACH-direct chain today; you bridge USDC in. Native USDC on mainnet at 0x20c000000000000000000000b9537d11c60e8b50. Programmatic wallet creation supported via TS/Go/Rust/Foundry SDKs. Explorer at explore.tempo.xyz.

For our purposes, the load-bearing fact: the mppx CLI provisions a Tempo testnet wallet with one command (npx mppx account create then npx mppx account fund). Production wallet provisioning follows the same pattern.

DimensionLink CLI (existing, set up 2026-04-29)MPP-via-Tempo (new)
Settlement assetCard (Amex 1008) or ACH (bank 3578) via Stripe SPTUSDC on Tempo (or any MPP-supported rail)
Approval gatePer-charge push to founder’s Link app, ~5min timeoutConfigurable — wallet-side spending caps + per-tx auth
Latency~90s human-in-loop today~0.6s machine-only (no human gate unless we add one)
Per-tx feeStripe interchange ~2.9% + $0.30 (card path)Tempo gas (~stable, USD-denominated, low; not yet quantified publicly) + Stripe MPP fees (not disclosed)
Merchant requirementMerchant accepts the SPT card credentialMerchant exposes MPP-compliant 402 endpoint
ReversibilityCard chargeback works; SPT boundedOn-chain stablecoin = irreversible, dispute via merchant only
Where it shinesSubscription top-ups, SaaS trials, anything humans want to gateMid-workflow micropurchases (Alpha Vantage pattern), high-frequency tiny calls
Today’s installed base✅ Wired and tested❌ Not provisioned yet, but link-cli binary already supports it

They are complementary, not competing. Link CLI is the human-gated card path. MPP-via-Tempo is the machine-only stablecoin path for high-frequency, low-stakes spend. Both can route through the same link-cli binary we already have. No migration is needed. We add MPP as a second mode alongside the existing per-charge approval flow.

Recommendation: Provision a Tempo wallet now (testnet first, mainnet next week), keep founder-approval gating for all live spend ≥ $5 until we calibrate. Total elapsed setup time ~30 min.

Why now: (a) we already have the buyer SDK installed (link-cli), so the marginal cost is low; (b) the Alpha Vantage/Collison demo is the canonical use case for MAC’s “agent-as-customer” thesis — eating our own dog food on the buyer side gives us first-hand pattern-library evidence; (c) L5-trajectory unhobbling — this is exactly the toolset the founder green-lit; (d) deferring means we keep showing up to client conversations explaining MPP in theory rather than from demo experience.

Why not “wait”: Stripe’s full MPP via PaymentIntents is in early access, but the buyer side is GA via the SDK + Tempo mainnet. We’re not waiting on a counterparty.

Wallet setup steps (lean path)

# 1. Testnet wallet — verifies the loop end-to-end with no real money
NPM_CONFIG_MIN_RELEASE_AGE=0 npm install -g @tempoxyz/mppx
npx mppx account create --network tempo-testnet
# Outputs: address + seed-phrase. Save BOTH to 1Password "Ray Agent" vault, entries:
#   - "Tempo Wallet — Testnet Address" (field: address)
#   - "Tempo Wallet — Testnet Seed" (field: credential, secret)
npx mppx account fund   # uses testnet faucet, free

# 2. Verify against any MPP-paywalled testnet endpoint
npx mppx http://test-endpoint.mpp.dev/sample

# 3. Mainnet wallet — only after testnet round-trip passes
npx mppx account create --network tempo-mainnet
# Save to 1Password as "Tempo Wallet — Mainnet Address" + "...Seed"

# 4. Bridge initial USDC funding
# Use Relay or LayerZero from existing Coinbase/wallet position to mainnet address
# Recommended initial fund: $50 (covers ~hundreds of micropurchases at expected unit cost)

MCP wrapper update: Add ~/.claude/scripts/mppx-wrapper.sh that fetches the Tempo seed from 1Password at MCP-launch time and exports MPPX_TESTNET_KEY / MPPX_MAINNET_KEY env vars. Same pattern as ~/Projects/stripe-mcp-wrapper/start.sh. Never .env on disk.

Spending controls + founder-approval gates

Tier system, mirroring the email-non-autonomy precedent (founder gates irreversible external actions until trust pattern established):

TierSpend per txDaily capApproval
Auto (initial)≤ $0.50$5/dayRay executes, logs to vault
Founder-confirm$0.50 – $25$50/dayiMessage heads-up + 60s implicit approve unless founder denies
Founder-explicit$25 – $250$200/dayiMessage explicit approval required, same flow as Link CLI today
Hard stop> $250n/aRefused; founder must escalate or use Link card path

Caps enforced inside ~/.claude/scripts/mppx-wrapper.sh BEFORE the SDK call (kill switch, not after-the-fact audit). Daily counter persisted at ~/.claude/state/mpp-daily-spend.json, resets at midnight ET.

Audit trail: every MPP transaction appended to ~/rdco-vault/04-tooling/mpp-transaction-log.md with merchant, amount, hash, Tempo explorer link, founder-approval status, business reason. Founder visibility = same surface as ray-operating-budget tag in the vault.

Credential storage + security posture

Cost estimate

ComponentCost
Setup (one-time)~30 min Ray time, $0 cash
Initial wallet funding$50 USDC bridged to Tempo (suggested; can be $20 to start)
Bridge fee (one-time)~$1-3 via Relay/Stargate (LayerZero)
Per-tx Tempo gas<$0.01 (stable USD-denominated, sub-cent expected based on Tempo’s “predictably low fees” guidance)
Per-tx Stripe MPP feeNot disclosed — Stripe has not published MPP pricing; treat as risk item
Monthly minimum$0 (no subscription)

Worst-case unit economics: if Stripe takes a per-tx fee of $0.05 (speculative), 100 micropurchases/mo = $5/mo + $1 in gas. Cheap.

Implementation roadmap

Phase 1 (this week, ~30 min): Testnet wallet, end-to-end loop verification against any test MPP endpoint. No real money at risk. Document the loop in this file.

Phase 2 (next week, ~30 min + $50): Mainnet wallet, $50 USDC bridged in, MCP wrapper script wired, spending caps enforced, audit log live. First real micropurchase: a $0.10 test buy from any MPP-paywalled service to verify mainnet flow. Founder gets iMessage on every tx for the first 5; auto-approve under $0.50 kicks in after pattern is established.

Phase 3 (when relevant, not yet scheduled): Seller-side MPP for MAC or Squarely. MAC is the natural fit — micro-paywalled audit reports / model audits sold to other agents. Cloudflare Workers MPP middleware makes this trivial since both surfaces are already on Workers. Defer until Phase 2 has produced 30 days of clean buyer-side data.

What this enables (L5-trajectory)

This is the buyer-side completion of the Vending-Bench “agent extends into atoms-world” pattern. With Link CLI + Tempo wallet + spending caps + audit trail, Ray can:

It also gives RDCO first-hand demo material for explaining MPP to enterprise prospects — the same agent-purchase-governance question phData et al. will face in 2026-2027.

Joins existing infra cluster:

What’s deferred

Alternatives considered + rejected

AlternativeWhy rejected
Skip MPP entirely, use only Link CLIMisses machine-only micropurchase use case (sub-dollar paywalls). Also forfeits L5 unhobbling and demo material.
Self-build MPP buyer client from specThe official mppx CLI exists. Building from scratch is engineering work for no marginal value.
Custodial wallet via a third party (e.g., Crossmint)Adds counterparty risk and an extra fee layer. Tempo wallet is self-custody by default; we already manage credentials in 1Password.
Wait for Stripe MPP-via-PaymentIntents GAThat’s the acceptance side; buyer side is shipped today. Waiting forfeits learning.
Use a non-Tempo settlement (Solana, Lightning) for cost reasonsTempo is the canonical Stripe-aligned chain; running on it gets us alignment with Stripe’s broader Agentic Commerce Suite. Other rails are layerable later via the same mppx CLI without changing the wallet model.

Open questions for founder

  1. Initial mainnet funding amount. $50 USDC is the recommended Phase 2 starting balance. Higher = more runway between top-ups; lower = tighter blast radius if a bug spends faster than expected. Founder pick.
  2. Auto-approve ceiling for Tier-1. Proposal: $0.50/tx, $5/day. Confirm or adjust.
  3. Card-fallback rule. When a merchant isn’t on MPP/Tempo (most still aren’t in May 2026), Ray defaults back to Link CLI card path. Founder OK with that auto-fallback or want explicit confirmation per merchant?

Phase 1 Execution Log — 2026-05-01 16:05 ET

Outcome: COMPLETE. Full MPP round-trip verified end-to-end against mpp.dev test endpoint on Tempo Moderato testnet, $0 real money spent, ~10 min of elapsed work.

Tooling install (no global install needed)

npx mppx --version    # auto-installs mppx@0.6.5 from npm to ~/.npm/_npx/, returns 0.6.5

Cached at ~/.npm/_npx/b9498644ff968c00/node_modules/mppx. The global npm install -g @tempoxyz/mppx step from the original proposal is not requirednpx mppx works out of the box and the proposal’s @tempoxyz/mppx package name was speculative. The actual published name is just mppx (the v0.6.5 binary; vendor unspecified in npm registry but fetched cleanly).

Wallet creation

npx mppx account create --account ray-testnet
# → Account "ray-testnet" saved to keychain.
# → Address 0x580A669D73F40e22d8b6a52AeD1d20CD319B1610

npx mppx account default --account ray-testnet
# → Default account set to "ray-testnet"

Address (testnet, safe to share): 0x580A669D73F40e22d8b6a52AeD1d20CD319B1610

Credential storage: mppx writes to macOS Keychain by default (NOT to a flat file on disk). The only file touched in ~/.config/mppx/ is default (11 bytes, contains the account name). Private key never lands on disk. This is materially better than the proposal assumed (we expected ~/.config/mppx/<account>.json) — keychain integration means even the testnet seed enjoys OS-level keystore protection. No need to rotate this into 1Password for testnet; for mainnet (Phase 2), the question becomes “1Password vs Keychain” rather than “1Password vs flat file.”

Funding (testnet faucet)

The default RPC is https://rpc.tempo.xyz (mainnet). Naive npx mppx account fund tried mainnet and failed with insufficient liquidity in FeeAMM pooltestnet RPC must be passed explicitly. The Moderato testnet RPC is https://rpc.moderato.tempo.xyz (chain ID 42431).

npx mppx account fund --account ray-testnet --rpcUrl https://rpc.moderato.tempo.xyz
# → Funding "ray-testnet" on testnet
#   0xf48993f9390284e21a44a23b8338d44e08a86ac46affd1020a54c8dc44fddc88
#   0x179945d084f208b6af41ff5adda75f7048fbd78a09aa8e56767b24a4e043f078
#   0xb767910bdfb755da441520851e12bfa23eb47b8407337e508fe83e899e940487
#   0x070b9f845ec45378069e0893613d4bbfb34c5a49365123e6581321aaf8404fb6
# → Funded successfully

Faucet drops 1,000,000 of each testnet stablecoin (PathUSD, AlphaUSD, BetaUSD, ThetaUSD) — verified via mppx account view:

Address  0x580A669D73F40e22d8b6a52AeD1d20CD319B1610
Balance  1_000_000 PathUSD (testnet)
         1_000_000 AlphaUSD (testnet)
         1_000_000 BetaUSD (testnet)
         1_000_000 ThetaUSD (testnet)

MPP round-trip purchase (the load-bearing test)

Endpoint: https://mpp.dev/api/ping/paid (the canonical sandbox endpoint advertised in the MPP quickstart docs).

npx mppx https://mpp.dev/api/ping/paid \
  --account ray-testnet \
  --rpcUrl https://rpc.moderato.tempo.xyz \
  -i -v

Two-leg HTTP exchange captured cleanly:

Leg 1 — server demands payment (HTTP 402):

HTTP/1.1 402 Payment Required
www-authenticate: Payment id="Y_6RM-oqzo0YypCJVzyw3aB86etxrQeM8C1ggWGRPH0",
  realm="mpp.sh", method="tempo", intent="charge",
  request="<base64-encoded payment request>",
  description="Ping endpoint access",
  expires="2026-05-01T20:10:44.134Z"

Decoded request (mppx pretty-prints it for us):

Leg 2 — mppx signs & re-requests, server returns content (HTTP 200):

HTTP/1.1 200 OK
payment-receipt: <base64 envelope decoding to>
  { method: "tempo", status: "success",
    timestamp: "2026-05-01T20:05:45.488Z",
    reference: "0xf7b54bd76e4bd6044784c101fc4b054350c8cd80c8bc00571e3f5e90657d83c8" }

Body: "tm! thanks for paying"

Transaction reference (testnet, Moderato chain ID 42431): 0xf7b54bd76e4bd6044784c101fc4b054350c8cd80c8bc00571e3f5e90657d83c8

Likely explorer URL (untested): https://explore.testnet.tempo.xyz/tx/0xf7b54bd76e4bd6044784c101fc4b054350c8cd80c8bc00571e3f5e90657d83c8

Total elapsed wall time of the two HTTP legs: ~1 second. This is the sub-second-finality story the Tempo + MPP marketing claims, observed first-hand. Compared to Link CLI’s ~90s human-in-loop per-charge approval, this is a different category of UX.

Deviations from the proposal’s plan

  1. Package name was speculative. Proposal said @tempoxyz/mppx; actual published npm package is mppx. Updated mental model.
  2. No global install needed. npx caches it; this is fine for our single-host operator pattern. Global install would be a nice-to-have for autocomplete only.
  3. Default RPC is mainnet, not testnet. Funding command silently tried mainnet and failed informatively. Anyone repeating this needs --rpcUrl https://rpc.moderato.tempo.xyz (or MPPX_RPC_URL env var) to hit testnet. Document this in the Phase 2 mainnet wrapper script so we don’t accidentally fund/spend on the wrong network.
  4. Credentials live in macOS Keychain, not in a config file. Better security posture than expected; reduces (but does not eliminate) the case for moving testnet keys to 1Password. Phase 2 should make a deliberate keychain-vs-1Password decision for mainnet.
  5. Phase 1 used mpp.dev/api/ping/paid (0.1 PathUSD) as the test endpoint. This is a real over-the-internet MPP server, not a locally-hosted toy. Confirms the protocol works end-to-end on a third-party host.

What this unlocks for Phase 2

Phase 2 (mainnet, $50 USDC funding, MCP wrapper, spending caps, audit log) is now a straight-line execution job — no protocol-layer unknowns remain. The buyer flow is proven; the open work is governance plumbing (caps, logs, kill switch) and the funding-rail decision (Relay/Stargate bridge from existing USDC position).

Key carry-over decisions for Phase 2 brief:

Phase 2 Execution Log — 2026-05-01 16:20 ET

Outcome: COMPLETE. Mainnet wallet provisioned, seed mirrored to 1Password as cold backup, wrapper script with cap enforcement built and smoke-tested. Awaiting founder action: $50 USDC seed transfer (step 7 below).

Mainnet wallet (shareable — public address)

Address:  0xD6714Effc5B580Ce4456bDCF33b118997eC2Adb2
Chain:    Tempo Mainnet (chainId 4217 = 0x1079)
RPC:      https://rpc.tempo.xyz

Verified live against the chain via eth_chainId RPC call (returned 0x1079 = 4217 ✓). Verified the wallet is reachable on mainnet via a smoke-test mppx invocation that reached the Tempo Mainnet TIP-20 contract (got back InsufficientBalance from the canonical USDC contract 0x20c0...0000 — expected, since balance is $0; what matters is the chain-side error confirms the wallet is wired correctly).

Credential storage (defense in depth)

Primary: macOS Keychain (mppx default behavior — confirmed in Phase 1, identical for mainnet).

Cold backup: 1Password “Ray Agent” vault

Wrapper script

Path: ~/.claude/scripts/mppx-wrapper.sh (executable, chmod 755)

Defense layers (in order):

  1. set -euo pipefail — fail loudly on any error.
  2. Keychain verification with 1Password fallback — checks security find-generic-password -s mppx -a ray-mainnet; if missing, fetches the private key from 1Password item xu2d6ms5pyw3htyxwbx66ckgoa and re-seeds the keychain. If both fail, aborts.
  3. Hard-locked RPC URL — exports MPPX_RPC_URL=https://rpc.tempo.xyz and MPPX_ACCOUNT=ray-mainnet. Even though these are mppx defaults, locking them defends against env var inheritance from a parent shell that might be set to testnet.
  4. Cap enforcement — for any URL argument, the wrapper:
    • GETs the URL with curl -s -i to capture the 402 challenge
    • Extracts the request="..." field from WWW-Authenticate: Payment header
    • Pads the base64 to a multiple of 4 (mpp.dev emits unpadded base64; macOS base64 -D silently truncates without padding) and decodes via Python
    • Parses amount (raw token units, USDC has 6 decimals → 100,000 = $0.10) and methodDetails.chainId
    • Rejects any chainId != 4217 (Tempo Mainnet only)
    • Rejects any per-tx amount > 50¢ (Tier-1 cap from proposal)
    • Rejects any cumulative daily spend > $5 (Tier-1 cap)
  5. State file at ~/.claude/state/mppx-daily-spend.json, keyed by YYYY-MM-DD in America/New_York time. Format: {"2026-05-01": 30, "2026-05-02": 0, ...} where the value is cents spent that day. Garbage-collects entries older than 14 days on each successful tx. Only successful payments increment — if mppx fails (e.g., insufficient balance, RPC error), the cap counter is NOT advanced.
  6. Logs to /tmp/mppx-wrapper.log with timestamps for every invocation, decision, and outcome.

Pass-through behavior: if the first arg is not an https?:// URL (e.g., account list, account view, sign), the wrapper passes through to npx mppx unchanged with exec.

Smoke-test results

All six tests run on 2026-05-01 16:19 ET, against the live wrapper on the live Tempo Mainnet RPC. Wrapper aborts cleanly with exit 1 in every reject case; pass-through works in every allow case.

TestSetupExpectedResult
Amppx-wrapper.sh https://mpp.dev/api/ping/paid (testnet chainId 42431)REJECT — wrong chain✓ “Refusing”, exit 1
BSynthetic 402 with $1.00 amount on chainId 4217REJECT — > per-tx cap✓ “exceeds per-tx cap of $0.50”, exit 1
CSynthetic 402 with $0.40 on chainId 4217 (no daily spend yet)Cap PASS, mppx attempts payment, fails on zero balance, state NOT incremented✓ Cap passed, mppx hit Tempo Mainnet (InsufficientBalance from 0x20c0... USDC contract — confirms wallet is on real mainnet), state file untouched
Dmppx-wrapper.sh account list (no URL)Pass-through✓ Lists ray-mainnet + ray-testnet correctly
EPre-seed state file with {"2026-05-01": 470}, then 40¢ tx on mainnetREJECT — would push to 510¢ > $5 daily cap✓ “would push today’s spend from 470¢ to 510¢, exceeding daily cap”, exit 1
FPre-seed state with 30¢, then 40¢ tx (under both caps)Cap PASS, mppx fails on balance, state still 30¢✓ Cap passed, payment failed (zero balance), state file remained {"2026-05-01": 30}

Cap-bypass attempts considered and verified blocked:

IP-restriction status (re: tracker file)

No update to ~/rdco-vault/04-tooling/2026-04-30-ip-restricted-policies-tracker.md needed. Tempo is a public chain — the wallet is identified by signature, not by source IP. Neither the Tempo RPC nor mppx exposes an IP-allowlist mechanism. Defense for the mainnet wallet relies on:

This is the same security posture as Phase 1 testnet — OS keystore + caps. The IP-restricted-policies tracker is the right place for things like the Stripe RAK (which DOES support IP allowlisting); MPP/Tempo categorically doesn’t fit there, and that’s noted intentionally.

Step 7 — Founder action: $50 USDC mainnet seed transfer

Recommended path: Coinbase → direct USDC bridge to Tempo via Relay (relay.link).

Reasoning (lowest-friction first):

  1. Coinbase + Relay (recommended) — Founder already has a Coinbase account with USDC balance (per 2026-04-29-link-cli-agent-wallet-setup context). Relay supports Tempo as a destination and bridges USDC natively in one tx, ~$1-3 fee, ~30s settlement. Steps: open relay.link, connect a wallet that holds the USDC (or use Coinbase Wallet’s WalletConnect), select source chain (Ethereum/Base/Arbitrum — wherever the USDC sits), destination chain Tempo, paste address 0xD6714Effc5B580Ce4456bDCF33b118997eC2Adb2, send $50 USDC. Confirm receipt via npx mppx account view --account ray-mainnet --rpc-url https://rpc.tempo.xyz.
  2. Stripe Link wallet → Tempo — Tempo support inside Link is not yet GA per Stripe’s blog (early access waitlist). Skip until GA.
  3. LayerZero Stargate — equivalent to Relay; comparable fees, slightly more clicks. Use as fallback if Relay is down.
  4. Stripe-managed on-ramp — would require setting up a buy-USDC-via-card flow, more friction than Coinbase-already-funded path.

Verification after transfer:

npx mppx account view --account ray-mainnet --rpc-url https://rpc.tempo.xyz
# Expected: Balance shows ~50 USDC (minus bridge fee, net ~$48-49)

Then a $0.10 micropurchase against any mainnet MPP endpoint via ~/.claude/scripts/mppx-wrapper.sh <url> will be the live-fire validation.

Phase 2 deviations from plan

  1. Wallet credential is a raw private key, not a 12/24-word mnemonic. The proposal language (“seed phrase”) was loose; mppx uses keystore-style 32-byte private keys. The 1Password item field is named private_key to match. No security implication — a private key is functionally equivalent to a mnemonic for restoration purposes.
  2. Chain ID confirmation: Tempo Mainnet is 4217 (0x1079), confirmed via live RPC call. Various community docs reference 6900; that is incorrect for mainnet (may be a testnet-variant or a stale doc). The wrapper hard-codes 4217.
  3. mppx pay subcommand does not exist — payment happens inline when fetching a 402-protected URL. The proposal’s reference to pay --dry-run was speculative. Cap enforcement is implemented by intercepting the 402 challenge ourselves (curl + base64 decode) before letting mppx do the actual signed re-request. This is more reliable than mppx sign --dry-run, which only validates challenge format and doesn’t return parsed amount.
  4. macOS base64 -D silently truncates unpadded input. Real-world test using mpp.dev/api/ping/paid revealed mpp.dev emits unpadded base64 (request="...In0" without trailing =). The Phase 1 success was a happy accident — its test endpoint happened to be 4-aligned. Wrapper now uses Python’s base64.b64decode which auto-handles padding.

Files touched in Phase 2

Carry-overs into Phase 3 / next operational notes

Funding Path Decision (2026-05-01 16:56 ET)

Founder asked: “Can we fund [the Tempo wallet] with Link instead of the roundabout Coinbase connection?”

Direct answer: NO — Link CLI cannot fund the Tempo wallet directly. It is structurally outbound-only.

Inspected the full command surface via link-cli --llms-full. Subcommand inventory: auth, demo, mpp (decode + pay), onboard, payment-methods (add + list), spend-request (create/retrieve/update/request-approval). There is no fund, deposit, transfer, send, or wallet subcommand. The wallet model is strictly card/ACH-on-file → spend-request → one-time SPT or virtual card credential consumed by an external merchant. Link wallet does not hold a Tempo USDC balance; it does not have an on-chain address; it cannot push USDC anywhere.

link-cli mpp pay <url> looks promising at first glance but is the opposite direction: it spends an approved spend request’s SPT against an MPP-paywalled URL via Stripe-managed rails. It uses Stripe’s MPP method (card SPT delivered over the 402 challenge), NOT Tempo USDC out of a self-custody wallet. The receiving merchant is paid by Stripe, not by an on-chain Tempo transfer to anyone’s address.

Confirmed by docs

The clean alternative the founder didn’t see: Stripe’s Crypto Onramp (separate product)

Stripe has a separate fiat→crypto on-ramp product (docs.stripe.com/crypto/onramp) that DOES let a user buy USDC with a card and have it delivered to an arbitrary self-custody address. But Tempo is not in the supported destination network list as of today — bitcoin, ethereum, solana, polygon, stellar, avalanche, base are listed; Tempo is not. So even the standalone on-ramp can’t deliver USDC directly to 0xD671...Adb2 on chainId 4217. We would still have to bridge from one of the supported chains → Tempo, which collapses back to roughly the same pattern as Coinbase + Relay (one fewer click, but adds a fresh KYC if the founder hasn’t used Stripe Onramp before — net worse than the Coinbase path he already has).

Path comparison for the $50 seed

PathMechanismFeeTimeFriction
A. Coinbase USDC → Relay → Tempo (recommended in Phase 2 log)Existing Coinbase USDC balance → relay.link bridges to Tempo address~$1-3~30sFounder already has the Coinbase account; one Relay flow
B. Link CLI directNOT POSSIBLE (no fund/send subcommand exists)
C. Stripe Crypto Onramp → bridge → TempoStripe-hosted onramp buys USDC on Base/Ethereum → bridge to Tempo~1.5% Stripe + bridge~minutesNew product setup, possible KYC, still requires bridge → no advantage over Path A
D. Wait for Link stablecoin GAweeks/monthsTechCrunch confirms it’s “coming,” not shipped

Recommendation

Stick with Path A. Coinbase → Relay to 0xD6714Effc5B580Ce4456bDCF33b118997eC2Adb2 is the straightest line we have today. The “roundabout” feel is real but unavoidable until either (a) Stripe Crypto Onramp adds Tempo as a destination network, or (b) Link wallet ships its stablecoin/Tempo balance feature (announced as roadmap at Sessions 2026, no GA date). When (a) happens, Path C becomes Path A’s equal; when (b) happens, the founder’s original instinct becomes the right answer. Until then, the bridge step is the cost of being early on Tempo.

Watch list (revisit if any of these change)

tempo CLI Fund Spike (2026-05-01)

Spike to check whether the official tempo CLI (separate from mppx/link-cli) offers a one-command funding path for an arbitrary mainnet address. Founder greenlit 17:06 ET; research-only, no funds moved.

Install

tempo wallet surface

Commands:
  login     Sign up or log in to your Tempo wallet
  refresh   Refresh your access key without logging out
  logout    Log out and disconnect your wallet
  whoami    Show who you are: wallet, balances, keys
  keys      List keys and their spending limits
  transfer  Transfer tokens to an address
  fund      Fund your wallet (testnet faucet or mainnet bridge)
  sessions  Manage payment sessions
  services  Browse the MPP service directory
  debug     Collect debug info for support

tempo wallet fund --help (verbatim)

Fund your wallet (testnet faucet or mainnet bridge)

Usage: tempo wallet fund [OPTIONS]

Options:
      --address <ADDRESS>  Wallet address to fund (defaults to current wallet)
      --no-browser         Do not attempt to open a browser
  -h, --help               Print help

tempo wallet transfer --help (verbatim)

Transfer tokens to an address

Usage: tempo wallet transfer [OPTIONS] <AMOUNT> <TOKEN> <TO>

Arguments:
  <AMOUNT>  Amount in human units ("1.00", "50")
  <TOKEN>   Token contract address (0x...)
  <TO>      Recipient address (0x...)

Options:
      --fee-token <FEE_TOKEN>  Pay fees in a different token (default: same token)
      --dry-run                Show plan + fee estimate, don't send

Examples:
  tempo wallet transfer 1.00 0x20c0...b50 0x70997...9C8
  tempo wallet transfer 50 0x20c0...b50 0x70997...9C8 --dry-run

Does tempo wallet fund --to <address> exist? PARTIAL

The shape is close but not what the spike hoped for:

KYC / pairing: funding is gated by whatever the Tempo Wallet web UI demands — same KYC/region rules as the failed mobile attempt. The CLI does not bypass them.

What this changes for our $50 USDC funding plan

Nothing material. tempo wallet fund --address 0xD6714Effc5B580Ce4456bDCF33b118997eC2Adb2 --no-browser would print the same wallet.tempo.xyz onramp URL the founder already tried on mobile — possibly more usable on desktop, but the underlying flow (KYC, region gates, current mobile bug) is unchanged.

tempo wallet transfer is crypto-to-crypto only (takes a token contract address as the second arg) — useful once we already have USDC on Tempo, useless for the fiat-on-ramp step.

Verdict

Fall back to Coinbase → Relay (Path A from the main proposal). The tempo CLI does not collapse the funding flow; it’s a thin launcher around the same web UI that’s already degraded for the founder. Worth keeping installed for tempo wallet whoami, tempo wallet transfer, and tempo wallet services once we have funds on Tempo, but it’s not a shortcut to getting funds onto Tempo.

One small upside worth trying first: before booting Coinbase + Relay, run tempo wallet fund --address 0xD6714Effc5B580Ce4456bDCF33b118997eC2Adb2 --no-browser from desktop. If the printed URL opens a working desktop onramp (the mobile bug may not repro on desktop), we save the bridge hop. Two-minute test, then bail to Path A if the desktop UI also fails.

Watch list addition