# Buying a Token Plan package

Everything you need, from a machine with nothing set up.

A **Token Plan** is a monthly credit allowance on Baidu AI Cloud, bought
through FluxA. It is billed once for the period and does not auto-renew.
After it settles you get an endpoint and an API key of your own.

| Plan | slug | Price | You get |
|---|---|---|---|
| Lite | `lite` | $18.00 | 20,000 Token Plan Credits, 1 month |
| Standard | `standard` | $56.00 | 60,000 Token Plan Credits, 1 month |
| Advanced | `advanced` | $131.50 | 150,000 Token Plan Credits, 1 month |

This page covers paying by **card**: the human approves a spending limit once,
then their card pays.

---

# Before you start

```bash
npm install -g @fluxa-pay/fluxa-wallet@latest
fluxa-wallet --version              # must be 0.5.0 or newer
```

0.4.x has no `CARD_USD`: every card command fails with "Unsupported currency",
which never mentions the version.

Go straight to Step 1. The approval page in Step 2 collects a card from the
human if they have none, so there is nothing to check or set up first.

---

## Step 1 — Create the order

This is the FluxA side. It fixes the price and produces an **attempt id**, which
is the only thing that crosses from FluxA to the wallet. Nothing is charged and
nothing is reserved yet.

It comes first because its response also names the merchant your mandate has to
be scoped to. Take those values from here rather than from this page, so a
signature can never be spent on a mismatch.

```bash
AUTH=$(fluxa-wallet agent-vc --audience fluxa-wallet-service \
  --challenge wallet-user-info-lookup --ttl 300 | jq -r .data.vc)

ORDER=$(curl -sS -X POST "https://router.fluxapay.xyz/pay/createOrder/tokenplan/<plan-slug>" \
  -H "Authorization: Bearer $AUTH")
ATTEMPT_ID=$(echo "$ORDER" | jq -r .attemptId)
STATUS_URL=$(echo "$ORDER" | jq -r .statusUrl)
M_NAME=$(echo "$ORDER" | jq -r .merchant.name)
M_URL=$(echo "$ORDER"  | jq -r .merchant.url)
M_CC=$(echo "$ORDER"   | jq -r .merchant.countryCode)
```

`checkoutUrl` comes back null, and that is correct here: on the card rail there
is no page for anyone to type a card into.

`<plan-slug>` is one of the slugs in the table at the top.
Nothing else in that path varies.

**Call this once.** It is not idempotent: every call makes another order.

## Step 2 — Ask the human for permission

A **mandate** is a permission slip: *FluxA may charge my card, up to this much,
for this long*. It is not a payment. Nothing is charged when you create it.

**If a signed mandate already exists, reuse it and skip to Step 4.** Read
**both** keys: filtered by `--host`/`--amount` this returns
`eligibleMandates`, unfiltered it returns `mandates`. Reading one finds
nothing and makes the human sign a mandate they already have.

```bash
fluxa-wallet linked-card mandates --host "${M_URL#https://}" --amount 1800 \
  | jq -r '((.eligibleMandates // .mandates // [])[0].mandateId) // empty'
```

**Set the limit to at least 3x the price.** The limit is a running total, not a
per-purchase amount. Every payment you start reserves its slice the moment it
starts, and keeps it until that payment finishes, including one the human walks
away from, which keeps its slice for good. A limit equal to the price therefore
buys exactly one attempt, and a retry costs another signature.

```bash
# $18.00 purchase -> $54.00 limit. The amount is in CENTS.
fluxa-wallet mandate-create --currency CARD_USD --amount 5400 --seconds 7200 \
  --desc "Lite Token Plan package on FluxA, up to \$54.00 total." \
  --merchant-name "$M_NAME" --merchant-url "$M_URL" --merchant-country "$M_CC" \
  --transaction-ref "$ATTEMPT_ID"
```

Pass the merchant through from the order exactly as it came. Those three values
are how the card network identifies FluxA and must match what is registered: a
wrong url fails with `MERCHANT_NOT_AVAILABLE`, a wrong name with
`MERCHANT_DETAILS_MISMATCH`, and neither gets better by retrying.

Give the human `data.authorizationUrl`. **Only they can open it**, and it stops
working after about 10 minutes.

## Step 3 — Wait until the card behind it is live

Signing is not the end of it. The wallet then has to activate a credential
against the card, and that part can fail on its own.

```bash
fluxa-wallet linked-card subcard --mandate <mandateId>
```

Ready is `status: signed`, `isReady: true`, `cardvault.canTransact: true`.
It usually takes about two minutes.

Know when to stop waiting:

- `status: failed` (often `lastErrorCode: CV_FAILED`): the mandate is dead.
  Make a new one and ask for another signature. It costs nothing.
- stuck on `authorizing` with no error: usually nobody pressed the button, or
  the link expired while the page sat open. Same fix.

Neither recovers on its own, so do not loop forever.

## Step 4 — Pay it

```bash
fluxa-wallet headless-checkout --mandate <mandateId> --attempt "$ATTEMPT_ID" \
  --billing @billing.json
```

`--billing` is the only thing you supply: firstName, lastName, address1, city,
state, country, zip. The wallet fills in the rest of the payment context itself.

`ACTION_REQUIRED` with `data.attempt.actionUrl` means the bank wants to see the
human. Send them the link; it works once.

From this moment the price is reserved against the mandate, whether or not the
human finishes. **Never submit this attempt again**, on failure, on a closed tab,
on anything. A retry means a brand-new order.

## Step 5 — Watch it settle

```bash
until [ "$(curl -sS "$STATUS_URL" -H "Authorization: Bearer $AUTH" | jq -r .status)" = "settled" ]; do
  sleep 5
  case "$AUTH" in ey*) AUTH=$(fluxa-wallet agent-vc --audience fluxa-wallet-service \
    --challenge wallet-user-info-lookup --ttl 300 2>/dev/null | jq -r '.data.vc // empty');; esac
done
```

Re-mint as you poll. That credential lasts five minutes and a card payment
usually takes longer, so a loop that does not renew starts getting Unauthorized
and looks exactly like a stuck order.

Done is `status: settled`.

The plan is set up after the money clears, so `settled` comes first and the
API key follows a moment later. Read it with:

```bash
curl -sS "https://router.fluxapay.xyz/llm/tokenplan/subscription" -H "Authorization: Bearer $AUTH" \
  | jq '.subscriptions[0]'
```

---

# When it does not work

There are three outcomes, not two.

**Declined.** Tell the human and stop.

**Approved.** Settled, the plan is set up.

**Nobody knows.** `PSP_UNKNOWN`, `RETRIEVE_UNKNOWN`, `CREDENTIAL_LOST`, or any
5xx or timeout. The processor never gave a definite answer, so **nobody can say
whether the card was charged**. That attempt is frozen permanently. Resubmitting
it is how a double charge happens. Trying again needs a brand-new order.

Expect this one. It is not rare.
