WalletFeed

Webhook format

A Webhook destination posts JSON to your HTTPS URL whenever transactions change. Requests come straight from your iPhone and are signed with Standard Webhooks, so any Standard Webhooks library can verify them.

Request

Body

{
  "type": "transactions.changed",
  "timestamp": "2026-10-27T17:41:21Z",
  "data": {
    "upserted": [
      {
        "id": "8B3F0C2E-6D7A-4E8F-9C1B-2A4D5E6F7A8B",
        "accountID": "4F1E2D3C-…",
        "accountName": "Apple Card",
        "accountType": "liability",
        "date": "2026-10-27T15:02:11Z",
        "amount": 6.75,
        "currencyCode": "USD",
        "direction": "debit",
        "description": "Blue Bottle Coffee",
        "originalDescription": "BLUE BOTTLE COFFEE OAKLAND CA",
        "merchantName": "Blue Bottle Coffee",
        "merchantCategoryCode": 5814,
        "category": "dining",
        "status": "pending",
        "type": "purchase"
      }
    ],
    "deletedIDs": []
  }
}

Send Test in WalletFeed posts the same shape with "type": "walletfeed.test" and one sample transaction.

Handling changes

Fields

FieldValue
idWallet's transaction ID. Stable across updates.
accountID, accountNameThe Wallet account, such as Apple Card.
accountTypeliability (Apple Card) or asset (Apple Cash, Savings).
date, postedDateISO 8601. postedDate appears once the charge posts, when Wallet provides it.
amountA positive number; direction gives the sign.
directiondebit (purchases, fees) or credit (refunds, payments, deposits).
currencyCodeISO 4217, such as USD. foreignAmount and foreignCurrencyCode appear for purchases in another currency.
description, originalDescriptionWallet's cleaned-up description, and the raw one from the network.
merchantName, merchantCategoryCodeWhen Wallet knows them. The category code is the card network's MCC.
categoryWalletFeed's category from the MCC: groceries, dining, transport, fuel, travel, shopping, entertainment, subscriptions, utilities, health, services, cash or other.
statusWallet's status: authorized, pending, booked or memo.
typeWallet's transaction type, such as purchase, refund, payment or transfer.

Fields without a value are left out.

Verify

Get the signing secret from Share Signing Secret in WalletFeed, on the setup screen or the destination's screen. It's whsec_ followed by base64. With a Standard Webhooks library:

// Node: npm install standardwebhooks
import { Webhook } from "standardwebhooks";
const payload = new Webhook(process.env.WALLETFEED_SECRET).verify(rawBody, request.headers);
# Python: pip install standardwebhooks
from standardwebhooks.webhooks import Webhook
payload = Webhook(os.environ["WALLETFEED_SECRET"]).verify(raw_body, request.headers)

Or by hand:

  1. Base64-decode the secret after whsec_.
  2. Compute HMAC-SHA256 of {webhook-id}.{webhook-timestamp}.{raw body} with it, and base64-encode the result.
  3. Compare it, in constant time, with the value after v1, in webhook-signature.
  4. Reject timestamps more than five minutes from now.

Verify the raw body exactly as received, before parsing it.