Skip to main content

Payment Cards

Manage user payment cards and perform deposits from cards to Paysera accounts.

Special Permissions Required

This feature requires special permissions and the cards OAuth scope to manage user payment cards.

What are Payment Cards?

Payment Cards in Wallet API allow users to:

  • 💳 Link payment cards to their Paysera accounts
  • 💰 Deposit funds from cards to accounts
  • 🔗 Manage card-account relationships
  • 📊 Track card status and commissions

Key Concepts

Card Statuses
StatusDescriptionActions Available
unrelatedCard created but not verifiedEdit, Delete, Relate
relatedCard verified and ready to useEdit, Delete, Deposit
failedCard verification failedDelete only
Card Lifecycle

Required Permissions

OAuth Scope

cards - Required to manage user's payment cards

Client Permissions

Special client permissions must be granted by Paysera support to use Payment Cards API.


Main Features

1. Card Management

Create Cards:

  • Link new payment cards to accounts
  • Initiate card verification process
  • Set card-account relationships

Edit Cards:

  • Update card-account links
  • Change card priority order

Delete Cards:

  • Remove cards from system
  • Available for all statuses
2. Card Verification

When a card is created, it starts with unrelated status:

  1. Create card via API
  2. Redirect user to verification page
  3. User enters card details securely
  4. Processing partner verifies card
  5. Status updates to related or failed
Asynchronous Process

Card verification is asynchronous. Poll the card status to check when verification completes.

3. Card Deposits

Transfer funds from verified cards to Paysera accounts:

Process:

  1. Create deposit request
  2. Specify amount and target account
  3. Process the deposit
  4. Commission is automatically calculated

Commission:

  • Charged on top of deposit amount
  • Based on commission rules
  • Varies by card type and amount

Quick Start Example

Basic Card Flow
import PayseraWalletClient from 'paysera-wallet-api';

const client = new PayseraWalletClient({
accessToken: 'your_access_token_with_cards_scope'
});

async function linkNewCard(userId, accountNumber) {
try {
// 1. Create card
const card = await client.createCard({
user_id: userId,
accounts: [{
number: accountNumber,
order: 1
}],
relation: {
redirect_back_uri: 'https://example.com/card-linked'
}
});

console.log('Card created:', card.id);
console.log('Redirect user to:', card.relation.redirect_uri);

// 2. Wait for user to complete verification
// (User is redirected, enters card details)

// 3. Poll for status
const relatedCard = await waitForCardRelation(card.id);

console.log('✅ Card verified and ready!');
return relatedCard;

} catch (error) {
console.error('Card setup failed:', error);
throw error;
}
}

async function waitForCardRelation(cardId, maxAttempts = 10) {
for (let i = 0; i < maxAttempts; i++) {
const card = await client.getCard(cardId);

if (card.status === 'related') {
return card;
}

if (card.status === 'failed') {
throw new Error('Card verification failed');
}

// Wait 2 seconds before next check
await new Promise(resolve => setTimeout(resolve, 2000));
}

throw new Error('Card verification timeout');
}

Card-Account Relationships

Priority Ordering

Cards can be linked to multiple accounts with priority order:

{
"accounts": [
{
"number": "EVP1234567890",
"order": 1 // Primary account
},
{
"number": "EVP9876543210",
"order": 2 // Backup account
}
]
}

Usage:

  • Lower order number = higher priority
  • Used for automatic deposits
  • Can be updated anytime

Commission Structure

How Commissions Work

Commissions are charged when depositing from cards:

Formula:

Total Charge = Deposit Amount + Commission
Commission = max(min_commission, Deposit × percent + fixed_amount)

Example:

// Commission rule: 2% + €0.10, min €0.50
Deposit:10.00
Commission: max(0.50,10.00 × 2% +0.10) =0.50
Total charged from card:10.50

Commission Fields

FieldDescription
percentPercentage fee (e.g., 2 for 2%)
fixFixed fee in cents
minMinimum commission in cents
maxMaximum commission in cents
currencyCommission currency

Security Considerations

Sensitive Data

🔒 Card details are NEVER sent to your server:

  • User enters card info on secure verification page
  • Processing partner handles card data
  • Your API only receives card ID and status

Best Practices

  1. Use HTTPS for all redirect URIs
  2. Validate card status before deposits
  3. Handle verification failures gracefully
  4. Don't store card numbers (use API IDs)
  5. Implement timeouts for verification polling

Common Use Cases

Use Case 1: Account Top-Up

Allow users to add funds to their Paysera account:

async function topUpAccount(cardId, accountNumber, amount) {
// Ensure card is related
const card = await client.getCard(cardId);
if (card.status !== 'related') {
throw new Error('Card not verified');
}

// Create deposit
const deposit = await client.createDeposit(cardId, {
account_number: accountNumber,
amount: {
amount: amount * 100, // Convert to cents
currency: 'EUR'
}
});

console.log(`Amount: €${deposit.amount.amount_decimal}`);
console.log(`Commission: €${deposit.commission.amount_decimal}`);
console.log(`Total: €${(parseFloat(deposit.amount.amount_decimal) +
parseFloat(deposit.commission.amount_decimal)).toFixed(2)}`);

// Process deposit
await client.processDeposit(deposit.id);

console.log('✅ Funds deposited successfully');
}
Use Case 2: Recurring Payments

Set up automatic recurring deposits:

class RecurringDeposit {
constructor(client, cardId, accountNumber) {
this.client = client;
this.cardId = cardId;
this.accountNumber = accountNumber;
}

async scheduleMonthly(amount) {
// Run on 1st of every month
const schedule = '0 0 1 * *'; // Cron format

// In production, use proper job scheduler
setInterval(async () => {
try {
await this.makeDeposit(amount);
} catch (error) {
console.error('Recurring deposit failed:', error);
await this.notifyUser(error);
}
}, 30 * 24 * 60 * 60 * 1000); // 30 days
}

async makeDeposit(amount) {
const deposit = await this.client.createDeposit(this.cardId, {
account_number: this.accountNumber,
amount: {
amount: amount * 100,
currency: 'EUR'
}
});

await this.client.processDeposit(deposit.id);

console.log(`Monthly deposit of €${amount} completed`);
}
}
Use Case 3: Multiple Cards Management

Let users manage multiple payment cards:

class CardManager {
constructor(client, userId) {
this.client = client;
this.userId = userId;
}

async listCards() {
const response = await this.client.getCards({
user_id: this.userId,
limit: 50
});

return response.cards.map(card => ({
id: card.id,
type: card.card_data?.type || 'Unknown',
number: card.card_data?.number || '****',
status: card.status,
isDefault: card.accounts?.[0]?.order === 1
}));
}

async setDefaultCard(cardId, accountNumber) {
// Get all user cards
const allCards = await this.listCards();

// Update orders
for (const card of allCards) {
const newOrder = card.id === cardId ? 1 :
(card.isDefault ? 2 : card.order + 1);

await this.client.editCard(card.id, {
accounts: [{
number: accountNumber,
order: newOrder
}]
});
}

console.log(`Card ${cardId} is now default`);
}

async removeCard(cardId) {
await this.client.deleteCard(cardId);
console.log(`Card ${cardId} removed`);
}
}

API Endpoints Overview

Card Management

EndpointMethodDescription
/rest/v1/cardPOSTCreate new card
/rest/v1/card/{id}GETGet card details
/rest/v1/card/{id}PUTEdit card
/rest/v1/card/{id}DELETEDelete card
/rest/v1/cardsGETList user's cards

Deposits

EndpointMethodDescription
/rest/v1/card/{id}/depositPOSTCreate deposit
/rest/v1/deposit/{id}/processPUTProcess deposit

Error Handling

Common Errors
ErrorCauseSolution
unauthorizedMissing cards scopeRequest proper scope
forbiddenNo card management permissionsContact support
not_foundInvalid card IDVerify card exists
invalid_stateCard status doesn't allow actionCheck card status first
Example Error Handling
async function safeDeposit(cardId, depositData) {
try {
// Check card status
const card = await client.getCard(cardId);

if (card.status !== 'related') {
throw new Error(`Card is ${card.status}, cannot deposit`);
}

// Create and process deposit
const deposit = await client.createDeposit(cardId, depositData);
await client.processDeposit(deposit.id);

return deposit;

} catch (error) {
if (error.code === 'not_found') {
console.error('Card not found');
} else if (error.code === 'invalid_state') {
console.error('Card verification incomplete');
} else if (error.code === 'insufficient_funds') {
console.error('Card has insufficient funds');
} else {
console.error('Deposit failed:', error.message);
}
throw error;
}
}

Next Steps

  1. 💳 Managing Cards - Create, edit, delete cards
  2. 💰 Card Deposits - Deposit from cards to accounts
  3. 🔐 Authentication - Setup OAuth
  4. 📖 API Reference - Complete API docs

Need Help?