3 4 5
Keys SDK Call Hooks Live
Step 3 of 5 ยท ~10 min

Make Your First API Call

Create a sandbox bank account object, initiate a test ACH debit transfer, and inspect the full API response. By the end of this step you'll have a real transfer ID in your terminal.

1
Create a bank account object

A bank account object represents the external bank account. In sandbox mode, use any routing number โ€” the API validates format, not real bank connectivity.

const { payments } = require('./lib/payments');

const account = await payments.bankAccounts.create({
  account_number: '000123456789',
  routing_number: '021000021', // JPMorgan Chase test routing
  account_type: 'checking',
  account_holder_name: 'Ramona Green',
  account_holder_type: 'individual'
});

console.log(account.id); // ba_xxxxxxxxxxxxxxxx
account = payments.bank_accounts.create(
    account_number="000123456789",
    routing_number="021000021",
    account_type="checking",
    account_holder_name="Ramona Green",
    account_holder_type="individual"
)

print(account.id)  # ba_xxxxxxxxxxxxxxxx
curl https://api.paymentsapi.dev/v1/bank-accounts \
  -H "Authorization: Bearer $PAYMENTS_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_number": "000123456789",
    "routing_number": "021000021",
    "account_type": "checking",
    "account_holder_name": "Ramona Green",
    "account_holder_type": "individual"
  }'
Response
{
  "id": "ba_3kLmNpQ8rStUvWxYz",
  "object": "bank_account",
  "account_holder_name": "Ramona Green",
  "account_type": "checking",
  "last4": "6789",
  "routing_number": "021000021",
  "status": "verified",
  "created_at": "2025-03-07T09:00:00Z"
}
2
Create an ACH transfer

Use the bank account ID from Task 1. Always include an idempotency_key to prevent duplicate transfers on retry.

const { randomUUID } = require('crypto');

const transfer = await payments.transfers.create({
  amount: 5000,             // amount in cents โ€” $50.00
  currency: 'usd',
  direction: 'debit',      // pull funds from the bank account
  payment_method: 'ach',
  bank_account_id: account.id,
  description: 'Test transfer',
  idempotency_key: randomUUID()
});

console.log(transfer.id);     // tr_xxxxxxxxxxxxxxxx
console.log(transfer.status); // "pending"
import uuid

transfer = payments.transfers.create(
    amount=5000,
    currency="usd",
    direction="debit",
    payment_method="ach",
    bank_account_id=account.id,
    description="Test transfer",
    idempotency_key=str(uuid.uuid4())
)

print(transfer.id)      # tr_xxxxxxxxxxxxxxxx
print(transfer.status)  # "pending"
curl https://api.paymentsapi.dev/v1/transfers \
  -H "Authorization: Bearer $PAYMENTS_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "amount": 5000,
    "currency": "usd",
    "direction": "debit",
    "payment_method": "ach",
    "bank_account_id": "ba_3kLmNpQ8rStUvWxYz",
    "description": "Test transfer"
  }'
ACH transfer status lifecycle
StatusMeaning
pendingTransfer created, not yet submitted to ACH network
processingSubmitted to ODFI, awaiting settlement (T+1 business day)
completedSettled โ€” funds received
returnedReturn received from RDFI (R01โ€“R33 return codes)
failedPre-submission validation failure
Step 3 Checklist
โ† Step 2