How it works

From API key to reconciled books in five steps.

WalletD is a REST API in front of a ledger of record. Here is the path a single payment takes, from onboarding a user to a movement your auditors can recompute.

How it works

The shape of an integration

  1. 1. Mirror your user

    Create a wallet user with your own external id. WalletD opens accounts per purpose (cash, points) the first time each is used, so there is nothing to provision up front.

  2. 2. Fund the wallet

    Start a top-up through Stripe. The balance is credited only when the gateway confirms with a signed webhook or a reconciliation query, never on a client callback.

  3. 3. Move the money

    Send peer-to-peer, take a payment with a hold, or split a marketplace sale. Every call carries an idempotency key and posts balanced legs to the ledger in one transaction.

  4. 4. Rewards and settlement follow

    Cashback and points are granted at the moment of capture; fees and commission are split; payouts produce a settlement statement. All of it posts to the same books.

  5. 5. Read and verify

    Read balances and history over the API, receive signed webhooks for every event, and let the built-in verifier re-check the ledger's invariants on a schedule.

Fund a wallet, then send money

Fund a wallet, then send money

The same request in six languages. Amounts are integer minor units; the ledger does the rest.

# Fund a wallet, then send money. Balances only move on the ledger.
curl -sS -X POST "$WALLETD_API/v1/users" \
  -H "Authorization: Bearer $WALLETD_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: usr-42-create" \
  -d '{"external_id":"user-42","kind":"consumer","display_name":"Ada Lovelace","handle":"ada"}'

curl -sS -X POST "$WALLETD_API/v1/transfers" \
  -H "Authorization: Bearer $WALLETD_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: xfer-ada-grace-001" \
  -d '{"from":"user-42","to":"@grace","amount":2500,"currency":"USD"}'
client := walletd.New(os.Getenv("WALLETD_API"), os.Getenv("WALLETD_API_KEY"))

var transfer walletd.Transfer
err := client.Do(ctx, http.MethodPost, "/v1/transfers", map[string]any{
    "from":     "user-42",
    "to":       "@grace",
    "amount":   2500, // minor units, $25.00, never a float
    "currency": "USD",
}, &transfer, "xfer-ada-grace-001") // idempotency key
if err != nil {
    return fmt.Errorf("transfer: %w", err)
}
client = WalletD()  # reads WALLETD_API / WALLETD_API_KEY

transfer = client.request(
    "POST",
    "/v1/transfers",
    {
        "from": "user-42",
        "to": "@grace",
        "amount": 2500,      # minor units, $25.00
        "currency": "USD",
    },
    idempotency_key="xfer-ada-grace-001",
)
print(transfer["status"])  # "settled"
const res = await fetch(`${API}/v1/transfers`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "xfer-ada-grace-001",
  },
  body: JSON.stringify({
    from: "user-42",
    to: "@grace",
    amount: 2500, // minor units, $25.00
    currency: "USD",
  }),
});
const transfer = await res.json();
$transfer = $walletd->request('POST', '/v1/transfers', [
    'from'     => 'user-42',
    'to'       => '@grace',
    'amount'   => 2500,      // minor units, $25.00
    'currency' => 'USD',
], idempotencyKey: 'xfer-ada-grace-001');

echo $transfer['status']; // "settled"
var body = Map.of(
    "from", "user-42",
    "to", "@grace",
    "amount", 2500,      // minor units, $25.00
    "currency", "USD");

Transfer transfer = client.post(
    "/v1/transfers", body, "xfer-ada-grace-001", Transfer.class);

Principles that hold at every step

Idempotent by default

Every money-moving call takes an idempotency key. Retries are safe; the ledger replays the stored result byte-for-byte.

Balanced in one transaction

Fees, holds, caps, and clawbacks are applied inside the same posting, so the books are never briefly wrong.

Confirmed, not assumed

Money moves on verified gateway confirmation and settles on the ledger, not on an optimistic client response.

Verified continuously

A scheduled verifier recomputes conservation, balances, and floors, and fails loudly the moment anything drifts.

Early access

Become a design partner.

We are working with a small number of teams building wallet and money products on WalletD. If that is you, let's talk. You will get direct access to the people who built it.