Skip to main content

Overview

The Core API provides a simple and minimal interface to manage customers, virtual cards, balances, and authentication.
Designed for fast integrations with clean requests and predictable responses.

Simple Payloads

Minimal request and response structures

Virtual Cards

Issue and manage virtual cards

Secure Access

Token-based authentication

Authentication

Login

Authenticate a user and receive an access token.
curl -X POST "https://api.example.com/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@email.com",
    "password": "password123"
  }'
Request Body
FieldTypeRequiredDescription
emailstringUser email address
passwordstringUser password
Response
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "userId": "usr_123"
}

Logout

Invalidate the current session and token.
curl -X POST "https://api.example.com/auth/logout" \
  -H "Authorization: Bearer YOUR_TOKEN"
Headers
Authorization: Bearer YOUR_TOKEN
Response
{
  "success": true
}
Always call logout when user signs out to invalidate the session token properly.

Customers

Create Customer

Create a basic customer profile.
curl -X POST "https://api.example.com/customers" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Juan Perez",
    "email": "juan@email.com"
  }'
Request Body
FieldTypeRequiredDescription
namestringCustomer full name
emailstringCustomer email
Response
{
  "customerId": "cus_001",
  "name": "Juan Perez",
  "email": "juan@email.com"
}
Important: Store the customerId - you’ll need it to assign cards and track transactions.

List Customers

Retrieve all customers in your account.
curl -X GET "https://api.example.com/customers" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "customers": [
    {
      "customerId": "cus_001",
      "name": "Juan Perez",
      "email": "juan@email.com"
    },
    {
      "customerId": "cus_002",
      "name": "Maria Garcia",
      "email": "maria@email.com"
    }
  ]
}

Virtual Cards

Create Virtual Card

Create a new virtual card with specified currency.
curl -X POST "https://api.example.com/cards" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "currency": "USD"
  }'
Request Body
FieldTypeRequiredDescription
currencystringCard currency: USD, EUR, COP
Response
{
  "cardId": "card_001",
  "status": "inactive",
  "currency": "USD"
}
New cards are created with inactive status. You must activate them before use.

Assign Card to Customer

Link a virtual card to a customer profile.
curl -X POST "https://api.example.com/cards/assign" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardId": "card_001",
    "customerId": "cus_001"
  }'
Request Body
FieldTypeRequiredDescription
cardIdstringVirtual card ID
customerIdstringCustomer ID to assign card
Response
{
  "success": true,
  "cardId": "card_001",
  "customerId": "cus_001"
}

Change Card Status

Activate, block, or cancel a virtual card.
curl -X PATCH "https://api.example.com/cards/status" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardId": "card_001",
    "status": "active"
  }'
Request Body
FieldTypeRequiredDescription
cardIdstringVirtual card ID
statusstringNew status: active, blocked, cancelled
Response
{
  "cardId": "card_001",
  "status": "active"
}
Status Transitions
Card is active and ready for transactions
  • ✅ Can make purchases
  • ✅ Can add balance
  • ✅ Can view movements
Cancelled status is permanent. Once cancelled, a card cannot be reactivated. Create a new card instead.

Balances

Add Balance

Add funds to a virtual card.
curl -X POST "https://api.example.com/balances/add" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardId": "card_001",
    "amount": 100
  }'
Request Body
FieldTypeRequiredDescription
cardIdstringVirtual card ID
amountnumberAmount to add (must be > 0)
Response
{
  "cardId": "card_001",
  "balance": 100
}
Balance is returned in the card’s currency. If card is USD, balance is in USD.

Transactions

List Movements

Retrieve transaction history for a specific card.
curl -X GET "https://api.example.com/cards/card_001/movements" \
  -H "Authorization: Bearer YOUR_TOKEN"
Response
{
  "movements": [
    {
      "id": "mov_001",
      "amount": -20,
      "description": "Online purchase - Amazon",
      "date": "2025-02-10T12:00:00Z"
    },
    {
      "id": "mov_002",
      "amount": 100,
      "description": "Balance top-up",
      "date": "2025-02-10T10:00:00Z"
    },
    {
      "id": "mov_003",
      "amount": -15.50,
      "description": "Subscription - Netflix",
      "date": "2025-02-09T18:30:00Z"
    }
  ]
}
Movement Fields
FieldTypeDescription
idstringUnique movement identifier
amountnumberTransaction amount (negative = debit, positive = credit)
descriptionstringTransaction description
datestringISO 8601 timestamp
Movements are returned in reverse chronological order (newest first).

Complete Integration Example

// 1. Login
const loginResponse = await fetch('https://api.example.com/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: 'admin@company.com',
    password: 'secure_password'
  })
});
const { token } = await loginResponse.json();

// 2. Create customer
const customerResponse = await fetch('https://api.example.com/customers', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'Juan Perez',
    email: 'juan@email.com'
  })
});
const { customerId } = await customerResponse.json();

// 3. Create virtual card
const cardResponse = await fetch('https://api.example.com/cards', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ currency: 'USD' })
});
const { cardId } = await cardResponse.json();

// 4. Assign card to customer
await fetch('https://api.example.com/cards/assign', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ cardId, customerId })
});

// 5. Add balance
await fetch('https://api.example.com/balances/add', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ cardId, amount: 500 })
});

// 6. Activate card
await fetch('https://api.example.com/cards/status', {
  method: 'PATCH',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ cardId, status: 'active' })
});

console.log('Card ready for use!');

Status Codes

CodeMeaningCommon Causes
200SuccessRequest completed successfully
400Bad RequestInvalid payload or missing required fields
401UnauthorizedMissing or invalid token
403ForbiddenToken expired or insufficient permissions
404Not FoundResource (customer, card) doesn’t exist
409ConflictCard already assigned, duplicate email, etc.
500Internal Server ErrorServer error - contact support

Common Issues

Problem: Authorization token is missing, invalid, or expiredSolutions:
    // ❌ BAD: No token
    fetch('https://api.example.com/customers')
    
    // ❌ BAD: Wrong format
    fetch('https://api.example.com/customers', {
      headers: { 'Authorization': token }
    })
    
    // ✅ GOOD: Proper Bearer format
    fetch('https://api.example.com/customers', {
      headers: { 'Authorization': `Bearer ${token}` }
    })
If token is expired, login again to get a new one.
Problem: Missing required fields or wrong data typesCommon mistakes:
    // ❌ BAD: Missing required field
    { name: 'Juan Perez' } // Missing email
    
    // ❌ BAD: Wrong data type
    { amount: "100" } // Should be number, not string
    
    // ❌ BAD: Invalid status
    { status: 'pending' } // Not a valid status
    
    // ✅ GOOD: Complete and valid
    {
      name: 'Juan Perez',
      email: 'juan@email.com'
    }
Problem: Using incorrect or non-existent IDsSolution: Always store IDs when they’re returned
    // Create and store customer ID
    const { customerId } = await createCustomer(...);
    localStorage.setItem('customerId', customerId);
    
    // Create and store card ID
    const { cardId } = await createCard(...);
    localStorage.setItem('cardId', cardId);
    
    // Use stored IDs
    await assignCard(cardId, customerId);
Problem: Trying to assign a card that’s already linked to another customerSolution: Check card status before assigning
    // Check if card is already assigned
    const card = await getCardDetails(cardId);
    
    if (card.customerId) {
      console.error('Card already assigned to:', card.customerId);
      // Create a new card instead
      const newCard = await createCard({ currency: 'USD' });
    }
Problem: Trying to add balance to inactive cardSolution: Check card status first
    // Get card status
    const card = await getCardDetails(cardId);
    
    if (card.status === 'cancelled') {
      throw new Error('Cannot add balance to cancelled card');
    }
    
    if (card.status === 'blocked') {
      // Activate card first
      await changeCardStatus(cardId, 'active');
    }
    
    // Now add balance
    await addBalance(cardId, 100);

Best Practices

Store Tokens Securely

Never expose tokens in logs or client-side code

Save All IDs

Store customerId, cardId in your database

Check Status

Verify card status before operations

Handle Errors

Always catch and log API errors

Logout Properly

Call logout endpoint when session ends

Validate Before

Validate data client-side before API calls

Security Notes

Token Security: Never expose authentication tokens in:
  • Git repositories
  • Client-side JavaScript
  • URL parameters
  • Console logs
  • Error messages
Do’s:
  • ✅ Use HTTPS for all requests
  • ✅ Store tokens in secure backend
  • ✅ Implement token refresh logic
  • ✅ Validate all inputs server-side
  • ✅ Log security events
  • ✅ Rotate credentials periodically
Don’ts:
  • ❌ Store tokens in localStorage (use httpOnly cookies instead)
  • ❌ Share tokens between users
  • ❌ Use same token across multiple sessions
  • ❌ Include sensitive data in URLs

Rate Limits

Rate limit: 1000 requests per hour per accountIf exceeded, you’ll receive a 429 Too Many Requests response.
Headers in response:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1644332400

Testing

Sandbox Environment

# Sandbox URL
https://api-sandbox.example.com

Test Credentials

{
  "email": "test@example.com",
  "password": "test123"
}

Test Cards

All cards created in sandbox mode are virtual and no real transactions occur.
Never use production credentials in sandbox or vice versa.

Next Steps