Skip to main content

Plaid Banking API

Integrate bank accounts via Plaid for ACH transfers, account linking, and wallet funding. Supports both sandbox and production environments with comprehensive connection management and transaction simulation capabilities.

POST/api/plaid/link-token/create

Create Link Token

Create a Plaid Link token for frontend connection flow. Generates secure token for user to connect their bank account via Plaid Link frontend component. Requires valid wallet_id and uses user_id from wallet lookup.

Parameters

wallet_idnumberrequired

Wallet ID to associate with bank connection

phone_numberstring

User phone number for Plaid verification (default: +1 415 5550123)

Request Body

{
  "wallet_id": 123,
  "phone_number": "+1 415 5550123"
}

Response

200Link token created successfully
{
  "status": "SUCCESS",
  "link_token": "link-sandbox-12345678-abcd-1234-5678-123456789abc",
  "expiration": "2024-01-15T11:30:00Z"
}
400Missing wallet_id
{
  "status": "FAILED",
  "message": "wallet_id is required"
}
404User not found for wallet
{
  "status": "FAILED",
  "message": "User not found for given wallet_id"
}
500Plaid API error
{
  "status": "FAILED",
  "message": "Error creating Plaid link token",
  "error": "Plaid service unavailable"
}
curl -X POST https://api.brdz.link/api/plaid/link-token/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
  "wallet_id": 123,
  "phone_number": "+1 415 5550123"
}'

Save Public Token

POST/api/plaid/link-token/exchange

Save Public Token from Frontend

Receive and log public token from Plaid Link frontend component. This is an intermediate step before exchanging for access token. Logs public token and metadata for processing.

Parameters

public_tokenstringrequired

Public token received from Plaid Link frontend

metadataobject

Metadata object from Plaid Link containing institution info

Request Body

{
  "public_token": "public-sandbox-12345678-abcd-1234-5678-123456789abc",
  "metadata": {
    "institution": {
      "name": "Chase",
      "institution_id": "ins_3"
    },
    "accounts": [
      {
        "id": "account_id",
        "name": "Checking Account",
        "type": "depository",
        "subtype": "checking"
      }
    ]
  }
}

Response

200Public token received successfully
{
  "status": "SUCCESS",
  "message": "Public token received"
}
400Missing public token
{
  "status": "FAILED",
  "message": "public_token is required"
}
curl -X POST https://api.brdz.link/api/plaid/link-token/exchange \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
  "public_token": "public-sandbox-12345678-abcd-1234-5678-123456789abc",
  "metadata": {
    "institution": {
      "name": "Chase",
      "institution_id": "ins_3"
    }
  }
}'

Exchange Public Token to Access Token

POST/api/plaid/item/public-token/exchange

Exchange Public Token to Access Token

Exchange public token for permanent access token and save connection to database. Creates entry in plaid_connections table with access token, item_id, and institution info. Logs connection event to plaid_connection_logs.

Parameters

public_tokenstringrequired

Public token from Plaid Link

metadataobject

Institution metadata from Plaid Link

Request Body

{
  "public_token": "public-sandbox-12345678-abcd-1234-5678-123456789abc",
  "metadata": {
    "institution": {
      "name": "Chase",
      "institution_id": "ins_3"
    }
  }
}

Response

200Token exchanged successfully
{
  "status": "SUCCESS",
  "access_token": "access-sandbox-12345678-abcd-1234-5678-123456789abc",
  "item_id": "item_12345678abcd1234567890123456"
}
400Missing public token
{
  "status": "FAILED",
  "message": "Missing public_token"
}
500Exchange failed
{
  "status": "FAILED",
  "message": "Failed to exchange public_token",
  "error": "Invalid public token"
}
200_already_connectedAlready connected (duplicate connection)
{
  "status": "ALREADY_CONNECTED",
  "access_token": "access-sandbox-12345678-abcd-1234-5678-123456789abc",
  "item_id": "item_12345678abcd1234567890123456"
}
curl -X POST https://api.brdz.link/api/plaid/item/public-token/exchange \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
  "public_token": "public-sandbox-12345678-abcd-1234-5678-123456789abc",
  "metadata": {
    "institution": {
      "name": "Chase",
      "institution_id": "ins_3"
    }
  }
}'

Check Plaid Connection

GET/api/plaid/{wallet_id}/check

Check Plaid Connection

Check if wallet is already connected to Plaid by looking up plaid_connections table. Returns boolean indicating connection status.

Parameters

wallet_idstringrequired

Wallet ID to check connection status (path parameter)

Response

200Connection status retrieved
{
  "connected": true
}
500Database error
{
  "error": "Gagal cek koneksi plaid",
  "details": "Database connection failed"
}
200_not_connectedNo connection found
{
  "connected": false
}
curl -X GET https://api.brdz.link/api/plaid/123/check \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY"

Disconnect Plaid (Combined)

DELETE/api/plaid/{wallet_id}/plaid

Disconnect Plaid Connection

Remove Plaid item from Plaid service and delete connection from database. Logs DISCONNECT action to plaid_connection_logs before removing from plaid_connections table.

Parameters

wallet_idstringrequired

Wallet ID to disconnect (path parameter)

Response

200Disconnected successfully
{
  "message": "✅ Plaid disconnected successfully"
}
400Invalid wallet ID
{
  "error": "wallet_id wajib diisi dan harus valid"
}
500Disconnect failed
{
  "error": "Gagal disconnect plaid",
  "details": "Plaid service error"
}
200_not_foundNo connection to disconnect
{
  "message": "Tidak ada koneksi plaid untuk wallet ini (sudah terhapus)"
}
curl -X DELETE https://api.brdz.link/api/plaid/123/plaid \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY"

Get Plaid Accounts

GET/api/plaid/{user_id}/accounts

Get Bank Accounts

Retrieve bank accounts from Plaid for connected user. Looks up access_token from plaid_connections table and calls Plaid accounts/get endpoint.

Parameters

user_idstringrequired

User ID to get accounts for (path parameter)

Response

200Accounts retrieved successfully
{
  "accounts": [
    {
      "account_id": "account_12345",
      "balances": {
        "available": 1000.5,
        "current": 1200.75,
        "iso_currency_code": "USD"
      },
      "name": "Checking Account",
      "type": "depository",
      "subtype": "checking",
      "mask": "0000"
    },
    {
      "account_id": "account_67890",
      "balances": {
        "available": 5000,
        "current": 5000,
        "iso_currency_code": "USD"
      },
      "name": "Savings Account",
      "type": "depository",
      "subtype": "savings",
      "mask": "1111"
    }
  ]
}
400Missing user ID
{
  "error": "user_id wajib diisi"
}
404No Plaid connection found
{
  "error": "Plaid connection tidak ditemukan untuk user ini"
}
500Plaid API error
{
  "error": "Gagal ambil akun Plaid",
  "details": "Plaid service unavailable"
}
curl -X GET https://api.brdz.link/api/plaid/123/accounts \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY"

Remove Plaid Item

POST/api/plaid/remove-item

Remove Plaid Item

Remove Plaid item from Plaid service only (does not remove from database). Use disconnect endpoint for complete removal.

Parameters

access_tokenstringrequired

Plaid access token for the item to remove

Request Body

{
  "access_token": "access-sandbox-12345678-abcd-1234-5678-123456789abc"
}

Response

200Item removed successfully
{
  "message": "Plaid item removed successfully",
  "data": {
    "removed": true
  }
}
400Missing access token
{
  "error": "access_token wajib diisi"
}
500Remove failed
{
  "error": "Gagal remove item",
  "details": "Invalid access token"
}
curl -X POST https://api.brdz.link/api/plaid/remove-item \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
  "access_token": "access-sandbox-12345678-abcd-1234-5678-123456789abc"
}'

Get Access Token by Wallet

GET/api/plaid/{wallet_id}/access-token

Get Access Token by Wallet

Retrieve Plaid access token for a specific wallet. Used for direct Plaid API calls from frontend or other services.

Parameters

wallet_idstringrequired

Wallet ID to get access token for (path parameter)

Response

200Access token retrieved
{
  "access_token": "access-sandbox-12345678-abcd-1234-5678-123456789abc"
}
404No connection found
{
  "error": "Plaid connection tidak ditemukan"
}
500Database error
{
  "error": "Gagal ambil access_token",
  "details": "Database query failed"
}
curl -X GET https://api.brdz.link/api/plaid/123/access-token \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY"

ACH Transfer Simulation

POST/api/plaid/transfer

Simulate ACH Transfer (Sandbox)

Simulate ACH transfer events in Plaid sandbox environment. Used for testing transfer workflows without real money movement.

Parameters

transfer_idstringrequired

Transfer ID to simulate

event_typestring

Event type to simulate (default: 'settled')

Request Body

{
  "transfer_id": "transfer_12345678abcd",
  "event_type": "settled"
}

Response

200Simulation successful
{
  "message": "Simulasi ACH Transfer 'settled' berhasil",
  "data": {
    "transfer_id": "transfer_12345678abcd",
    "event_type": "settled",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}
400Missing transfer ID
{
  "error": "transfer_id wajib diisi"
}
500Simulation failed
{
  "error": "Gagal simulasi transfer",
  "details": "Invalid transfer_id"
}
curl -X POST https://api.brdz.link/api/plaid/transfer \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
  "transfer_id": "transfer_12345678abcd",
  "event_type": "settled"
}'

SEPA Payment Simulation

POST/api/plaid/payment

Simulate SEPA Payment (Sandbox)

Simulate SEPA payment completion in Plaid sandbox environment. Used for testing European payment workflows.

Parameters

payment_idstringrequired

Payment ID to simulate completion

Request Body

{
  "payment_id": "payment_12345678abcd"
}

Response

200Simulation successful
{
  "message": "Simulasi SEPA Payment COMPLETED berhasil",
  "data": {
    "payment_id": "payment_12345678abcd",
    "status": "COMPLETED",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}
400Missing payment ID
{
  "error": "payment_id wajib diisi"
}
500Simulation failed
{
  "error": "Gagal simulasi payment",
  "details": "Invalid payment_id"
}
curl -X POST https://api.brdz.link/api/plaid/payment \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
  "payment_id": "payment_12345678abcd"
}'

Plaid Topup

POST/api/plaid/topup

Topup Wallet via Plaid

Fund wallet using connected bank account through Plaid. Creates transaction record using transactionModel with type 'TOPUP' and status 'SUCCESS_RECEIVED'. Logs to transaction history.

Parameters

wallet_idnumberrequired

Wallet ID to fund

amountnumberrequired

Amount to transfer in USD

currencystring

Currency code (default: 'USD')

Request Body

{
  "wallet_id": 123,
  "amount": 500,
  "currency": "USD"
}

Response

200Topup successful
{
  "status": "SUCCESS",
  "transaction_id": "TXN-1705317000-1234"
}
400Missing required fields
{
  "status": "FAILED",
  "message": "wallet_id dan amount wajib diisi"
}
404No Plaid connection found
{
  "status": "FAILED",
  "message": "Koneksi Plaid tidak ditemukan untuk wallet ini"
}
500Topup failed
{
  "status": "FAILED",
  "message": "Gagal topup via Plaid",
  "error": "Transaction processing error"
}
curl -X POST https://api.brdz.link/api/plaid/topup \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
  "wallet_id": 123,
  "amount": 500.00,
  "currency": "USD"
}'

Integration Flow

Complete Plaid Integration Workflow

  1. Frontend Integration:

    // 1. Create link token
    const linkToken = await createLinkToken({ wallet_id: 123 });

    // 2. Initialize Plaid Link (frontend)
    const handler = Plaid.create({
    token: linkToken.link_token,
    onSuccess: async (public_token, metadata) => {
    // 3. Save public token
    await savePublicTokenFromFrontend({ public_token, metadata });

    // 4. Exchange for access token
    await exchangePublicTokenToAccessToken({ public_token, metadata });
    }
    });
  2. Connection Management:

    // Check connection status
    const isConnected = await checkPlaidConnection('123');

    // Get bank accounts
    if (isConnected.connected) {
    const accounts = await getPlaidAccounts('user_123');
    }

    // Disconnect when needed
    await disconnectPlaidCombined('123');
  3. Funding Workflow:

    // Fund wallet from bank account
    const topup = await plaidTopup({
    wallet_id: 123,
    amount: 500.00,
    currency: 'USD'
    });

Database Tables Used

Based on controller implementation:

  • plaid_connections: Main connection storage (user_id, wallet_id, access_token, item_id, institution info)
  • plaid_connection_logs: Audit trail (CONNECT/DISCONNECT actions)
  • wallets: Wallet ownership verification
  • transactions: Topup transaction logging (via transactionModel)

Environment Configuration

Required environment variables:

PLAID_CLIENT_ID=your_plaid_client_id
PLAID_SECRET=your_plaid_secret_key
# Uses sandbox environment by default

Error Handling

All endpoints follow standard AOL error format:

  • SUCCESS: { status: "SUCCESS", data: {...} }
  • FAILED: { status: "FAILED", message: "...", error: "..." }
  • Database errors: { error: "...", details: "..." }

Sandbox vs Production

  • Sandbox: Uses PlaidEnvironments.sandbox for testing
  • Test institutions: Available in sandbox for development
  • Simulation endpoints: ACH Transfer and SEPA Payment for testing

Authentication Required

All endpoints require valid JWT token + API key. Wallet operations verify ownership through database lookups.

Plaid Link Frontend

This API works with Plaid Link frontend component. Create link token server-side, initialize Plaid Link client-side, then exchange tokens server-side.

Connection Management

Use check endpoint before attempting operations. Always disconnect properly to clean up both Plaid service and database records.