API template library

Plaid Transactions mock API and live sandbox

A WireMock simulation of Plaid's REST API — covering transaction pulls, incremental sync, recurring streams, and merchant enrichment.

Vendor
Plaid
Functionality
Transactions, enrichment, recurring streams
Spec version
2020-09-14_1.688.6
Endpoints
6
Stubs
7
Protocol
REST
Validation
AI-validated Before publication, an AI agent exercised these endpoints against the real Plaid API through WireMock's recording proxy, and the recorded traffic was used to verify each stub's request and response shapes.

Live sandbox · no signup, no API key

Plaid Transactions

A running WireMock Cloud instance of this template, callable right now from a terminal, a script, or an AI agent.

Base URL
https://98oy8.wiremockapi.cloud

POST Get Transactions

curl -s -X POST 'https://98oy8.wiremockapi.cloud/transactions/get' \
  -H 'Content-Type: application/json' \
  -d '{}'

POST Sync Transactions - page 1

curl -s -X POST 'https://98oy8.wiremockapi.cloud/transactions/sync' \
  -H 'Content-Type: application/json' \
  -d '{}'

POST Get Recurring Transactions

curl -s -X POST 'https://98oy8.wiremockapi.cloud/transactions/recurring/get' \
  -H 'Content-Type: application/json' \
  -d '{}'
Method Path Summary
POST /categories/get (Deprecated) Get legacy categories
POST /transactions/enrich Enrich locally-held transaction data
POST /transactions/get Get transaction data
POST /transactions/recurring/get Fetch recurring transaction streams
POST /transactions/refresh Refresh transaction data
POST /transactions/sync Get incremental transaction updates on an Item

Unauthenticated WireMock Cloud demo sandbox for Plaid — not an official Plaid sandbox, and it returns simulated example data only.

What's inside the Transactions template

The centerpiece is /transactions/sync, and it paginates for real: the first call returns two added transactions with has_more true and a next cursor, the follow-up call with that cursor closes the loop — has_more false, nothing further — so incremental-sync code runs its complete fetch-until-drained cycle against the mock. The transactions themselves are fully fleshed Plaid objects: a Whole Foods grocery debit and a United Airlines refund on a First Platypus Bank checking account, each carrying the personal_finance_category taxonomy, payment_meta, and location blocks down to their null-valued fields.

  • Incremental sync — a genuine two-page cursor walk with added, modified, and removed arrays
  • Transaction pulls — /transactions/get with the account context and a total_transactions count
  • Recurring streams — a monthly Netflix outflow with frequency, average amount, and a predicted next date
  • Enrichment — /transactions/enrich returning your submitted transactions with counterparty data attached
  • Maintenance routes — the /refresh acknowledgement and the deprecated /categories/get taxonomy

Example implementation using plaid-python

Because the sync cursors genuinely advance, the canonical plaid-python pagination loop — the one Plaid's docs recommend — terminates on its own against the sandbox:

The loop's exit condition is exactly what flaky live data makes hard to test — here it trips deterministically on the second iteration, every run. Move the host to a WireMock Cloud copy when you want more pages, a removed-transaction event, or a mid-sync error injected into the walk.

Categorization logic is the other winner: with merchant names, amounts, and personal-finance categories pinned, a budgeting feature's rollup math can be asserted to the cent without a live Item's transaction history shifting underneath it.

import plaid
from plaid.api import plaid_api
from plaid.model.transactions_sync_request import TransactionsSyncRequest

configuration = plaid.Configuration(
    host="https://98oy8.wiremockapi.cloud",
    # required by the client, ignored by the mock
    api_key={"clientId": "any-value", "secret": "any-value"},
)
client = plaid_api.PlaidApi(plaid.ApiClient(configuration))

cursor = ""
while True:
    resp = client.transactions_sync(
        TransactionsSyncRequest(access_token="access-sandbox-123", cursor=cursor)
    )
    for txn in resp.added:
        print(txn.name, txn.amount)
    if not resp.has_more:
        break
    cursor = resp.next_cursor

Frequently asked questions

Yes — the cursor from page one leads to a page whose has_more is false, so a well-written loop exits after two iterations. That makes the sandbox a safe target for the exact code path Plaid warns about: a paginator that ignores has_more or mishandles the final cursor shows up immediately as a hung test.

The complete documented shape — the stub builds its response out of your submitted transactions, echoing each id, description, amount, and currency back with a Whole Foods counterparty block attached. Send a skeletal body and you get a templating failure on a 500 rather than a Plaid validation error, so keep the request well-formed even though nothing authenticates it.

No — a mock answers requests, it doesn't originate them. Trigger your sync handler directly in tests, or post synthetic webhook payloads to your own endpoint; the mock's role is to serve the deterministic sync pages your handler then consumes.

The same First Platypus Bank checking fixture — mask 0000, the Plaid Gold Standard official name — anchors the Accounts & Balance template too, so a test suite that joins transactions to account metadata can run against both sandboxes with consistent identifiers.

Vendor names identify APIs represented by WireMock template sources. This page does not imply vendor endorsement, certification, partnership, or official integration status.