List Payins

Overview

Retrieve a paginated list of all payment charges (payins) for your organization. Use this endpoint to:

  • View all payments received
  • Filter payments by status
  • Build transaction history dashboards
  • Reconcile payments with your internal systems
  • Export payment data for accounting

A payin (also called a charge) represents any incoming payment from a customer.


Authentication

Type: API Key (required)

Required Headers

Header Required Description
Authorization Yes Format: Bearer sk_test_... or Bearer sk_live_...

Request

Method & Path

GET /api/v1/payments/payins

Query Parameters

Parameter Type Required Default Description
limit integer No 50 Number of results per page (1-100)
offset integer No 0 Number of results to skip (for pagination)
status_filter string No - Filter by status (e.g., COMPLETED, FAILED)

Example Requests

Get first 50 payins:

curl https://api.usesyncpay.com/api/v1/payments/payins \
  -H "Authorization: Bearer sk_live_abc123xyz..."

Get next page (51-100):

curl "https://api.usesyncpay.com/api/v1/payments/payins?limit=50&offset=50" \
  -H "Authorization: Bearer sk_live_abc123xyz..."

Get only completed payments:

curl "https://api.usesyncpay.com/api/v1/payments/payins?status_filter=COMPLETED" \
  -H "Authorization: Bearer sk_live_abc123xyz..."

Get 20 failed payments:

curl "https://api.usesyncpay.com/api/v1/payments/payins?status_filter=FAILED&limit=20" \
  -H "Authorization: Bearer sk_live_abc123xyz..."

Response

200 – Success

Returns a paginated list of payins.

{
  "total": 342,
  "items": [
    {
      "charge_id": "chr_1a2b3c4d5e6f",
      "checkout_id": "chk_9x8y7z6w5v",
      "organization_id": "org_abc123",
      "amount": "75000.00",
      "currency": "NGN",
      "status": "COMPLETED",
      "payment_provider": null,
      "provider_reference": "REF-12345",
      "created_at": "2026-01-24T14:30:00.000Z",
      "updated_at": "2026-01-24T14:35:00.000Z"
    },
    {
      "charge_id": "chr_2b3c4d5e6f7g",
      "checkout_id": "chk_8y7z6w5v4u",
      "organization_id": "org_abc123",
      "amount": "50.00",
      "currency": "USD",
      "status": "COMPLETED",
      "payment_provider": null,
      "provider_reference": "REF-67890",
      "created_at": "2026-01-24T13:15:00.000Z",
      "updated_at": "2026-01-24T13:20:00.000Z"
    }
  ]
}

Response Fields

Field Type Description
total integer Total number of payins matching the filter
items array Array of payin objects (max length based on limit)
items[].charge_id string Unique charge identifier
items[].checkout_id string Associated checkout session ID
items[].organization_id string Your organization ID
items[].amount string Payment amount
items[].currency string Payment currency
items[].status string Current payment status
items[].payment_provider string|null Payment provider (not exposed for security)
items[].provider_reference string Transaction reference ID
items[].created_at string ISO 8601 timestamp of creation
items[].updated_at string ISO 8601 timestamp of last update

400 – Bad Request

Invalid query parameters.

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid query parameters",
    "details": {
      "limit": "Must be between 1 and 100",
      "offset": "Must be non-negative"
    }
  }
}

401 – Unauthorized

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid API key"
  }
}

Pagination

How Pagination Works

Use limit and offset to paginate through results:

  • limit: How many results per page (1-100)
  • offset: How many results to skip

Example: To get page 3 with 50 results per page:

  • offset = (page - 1) × limit = (3 - 1) × 50 = 100
  • limit = 50
curl "https://api.usesyncpay.com/api/v1/payments/payins?limit=50&offset=100"

Calculating Total Pages

const totalPages = Math.ceil(response.total / limit);

Building a Paginator

async function getAllPayins(statusFilter = null) {
  const limit = 50;
  let offset = 0;
  let allPayins = [];
  let hasMore = true;
  
  while (hasMore) {
    const url = new URL('https://api.usesyncpay.com/api/v1/payments/payins');
    url.searchParams.append('limit', limit);
    url.searchParams.append('offset', offset);
    if (statusFilter) {
      url.searchParams.append('status_filter', statusFilter);
    }
    
    const response = await fetch(url, {
      headers: {
        'Authorization': 'Bearer sk_live_abc123xyz...'
      }
    });
    
    const data = await response.json();
    allPayins = allPayins.concat(data.items);
    
    // Check if there are more pages
    hasMore = data.items.length === limit;
    offset += limit;
  }
  
  return allPayins;
}

// Get all completed payments
const completedPayins = await getAllPayins('COMPLETED');
console.log(`Total completed payins: ${completedPayins.length}`);

Filtering by Status

Use status_filter to get payins in a specific status:

Available Status Filters

Status Description
COMPLETED Successfully completed payments
PENDING Awaiting customer action
AWAITING_PAYMENT Customer initiated, waiting for confirmation
PROCESSING Payment being processed
FAILED Failed payments
CANCELLED Cancelled by customer
EXPIRED Expired before completion
REFUNDED Refunded payments

Example: Get Only Failed Payments

async function getFailedPayments() {
  const response = await fetch(
    'https://api.usesyncpay.com/api/v1/payments/payins?status_filter=FAILED&limit=100',
    {
      headers: {
        'Authorization': 'Bearer sk_live_abc123xyz...'
      }
    }
  );
  
  const data = await response.json();
  
  console.log(`Found ${data.total} failed payments`);
  
  // Analyze failure reasons
  for (const payin of data.items) {
    const details = await getChargeDetails(payin.charge_id);
    console.log(`Charge ${payin.charge_id} failed:`, details.status_history);
  }
}

Example Use Case

Scenario: Your business dashboard needs to display a comprehensive transaction history showing all payments received. You need to build a paginated view that allows users to browse through completed payments, filter by status, and export transaction data for accounting purposes. The system should handle large volumes of transactions efficiently.

Implementation:

// Backend API
app.get('/api/transactions', async (req, res) => {
  const page = parseInt(req.query.page) || 1;
  const limit = 20;
  const offset = (page - 1) * limit;
  
  const response = await fetch(
    `https://api.usesyncpay.com/api/v1/payments/payins?` +
    `status_filter=COMPLETED&limit=${limit}&offset=${offset}`,
    {
      headers: {
        'Authorization': `Bearer ${process.env.SYNCPAY_API_KEY}`
      }
    }
  );
  
  const data = await response.json();
  
  res.json({
    transactions: data.items,
    totalPages: Math.ceil(data.total / limit),
    currentPage: page,
    totalTransactions: data.total
  });
});

// Frontend
async function loadTransactions(page = 1) {
  const response = await fetch(`/api/transactions?page=${page}`);
  const data = await response.json();
  
  // Display transactions
  displayTransactions(data.transactions);
  
  // Render pagination
  renderPagination(data.currentPage, data.totalPages);
}

Sorting and Ordering

Payins are returned in reverse chronological order (newest first) based on created_at.

  • Most recent payments appear first
  • Pagination maintains this order across pages

Example: First page shows payins from today, last page shows oldest payins.


Performance Considerations

Limit Recommendations

Use Case Recommended Limit
Web dashboard (user-facing) 20-50
Admin panel 50-100
Bulk export/processing 100
Real-time monitoring 10-20

Caching Strategies

For dashboards, consider caching results:

const cache = new Map();
const CACHE_TTL = 60000; // 1 minute

async function getCachedPayins(statusFilter, limit, offset) {
  const cacheKey = `${statusFilter}-${limit}-${offset}`;
  const cached = cache.get(cacheKey);
  
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }
  
  const data = await fetchPayins(statusFilter, limit, offset);
  cache.set(cacheKey, {
    data: data,
    timestamp: Date.now()
  });
  
  return data;
}

Getting Detailed Information

This endpoint returns summary information. To get full details (including metadata, fees, status history):

async function getPayinsWithDetails(limit = 50) {
  // 1. Get list of payins
  const listResponse = await fetch(
    `https://api.usesyncpay.com/api/v1/payments/payins?limit=${limit}`,
    { headers: { 'Authorization': 'Bearer sk_live_...' } }
  );
  const list = await listResponse.json();
  
  // 2. Get details for each payin
  const detailedPayins = await Promise.all(
    list.items.map(async (payin) => {
      const detailResponse = await fetch(
        `https://api.usesyncpay.com/api/v1/payments/charges/${payin.charge_id}`,
        { headers: { 'Authorization': 'Bearer sk_live_...' } }
      );
      return await detailResponse.json();
    })
  );
  
  return detailedPayins;
}

Note: Be mindful of rate limits when fetching details for many payins.


Export Example

Export all completed payments to CSV:

async function exportPayinsToCsv() {
  const limit = 100;
  let offset = 0;
  let rows = ['Charge ID,Amount,Currency,Status,Created At,Reference'];
  
  while (true) {
    const response = await fetch(
      `https://api.usesyncpay.com/api/v1/payments/payins?` +
      `status_filter=COMPLETED&limit=${limit}&offset=${offset}`,
      { headers: { 'Authorization': 'Bearer sk_live_...' } }
    );
    
    const data = await response.json();
    
    if (data.items.length === 0) break;
    
    // Add rows
    for (const payin of data.items) {
      rows.push([
        payin.charge_id,
        payin.amount,
        payin.currency,
        payin.status,
        payin.created_at,
        payin.provider_reference
      ].join(','));
    }
    
    offset += limit;
  }
  
  // Write to file or return as string
  return rows.join('\n');
}

Important Notes

Environment Separation

Test and live mode payins are completely separate:

  • sk_test_... returns test mode payins only
  • sk_live_... returns live mode payins only

Rate Limits

Be mindful of rate limits when paginating through large datasets:

  • Standard tier: 100 requests per minute
  • Consider implementing exponential backoff for bulk operations

Consistency

The total count may change between requests if:

  • New payments are received
  • Payments change status (e.g., PENDING → COMPLETED)

For consistent pagination, consider:

  • Caching the initial result set
  • Using timestamp-based filtering (coming soon)


Next Steps

After retrieving payins:

  1. Build dashboards showing revenue and transaction trends
  2. Reconcile payments with your internal order system
  3. Generate reports for accounting and financial analysis
  4. Monitor failed payments to identify issues
  5. Set up webhooks for real-time notifications (see Webhook Documentation)