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
Field Type Required Description emailstring ✅ User email address passwordstring ✅ User 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
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
Field Type Required Description namestring ✅ Customer full name emailstring ✅ Customer 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
Field Type Required Description currencystring ✅ Card 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
Field Type Required Description cardIdstring ✅ Virtual card ID customerIdstring ✅ Customer 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
Field Type Required Description cardIdstring ✅ Virtual card ID statusstring ✅ New 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
Card is temporarily blocked
❌ Cannot make purchases
✅ Can add balance
✅ Can view movements
✅ Can reactivate later
Card is permanently cancelled
❌ Cannot make purchases
❌ Cannot add balance
✅ Can view past movements
❌ Cannot reactivate
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
Field Type Required Description cardIdstring ✅ Virtual card ID amountnumber ✅ Amount 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
Field Type Description idstring Unique movement identifier amountnumber Transaction amount (negative = debit, positive = credit) descriptionstring Transaction description datestring ISO 8601 timestamp
Movements are returned in reverse chronological order (newest first).
Complete Integration Example
JavaScript - Full Flow
Python - Full Flow
// 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
Code Meaning Common Causes 200 Success Request completed successfully 400 Bad Request Invalid payload or missing required fields 401 Unauthorized Missing or invalid token 403 Forbidden Token expired or insufficient permissions 404 Not Found Resource (customer, card) doesn’t exist 409 Conflict Card already assigned, duplicate email, etc. 500 Internal Server Error Server error - contact support
Common Issues
401 - Token invalid or expired
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.
400 - Invalid request payload
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'
}
404 - Card or customer not found
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 );
409 - Card already assigned
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' });
}
Cannot add balance to blocked/cancelled card
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