Payments API - Notes and Clarifications
This document highlights important information about the Payments API that may not be immediately obvious from individual endpoint documentation.
Terminology Clarification
Charge vs Payin
These terms are used interchangeably in the SyncPay API:
- Charge: The technical term for a payment transaction record
- Payin: Business term for incoming payments (money coming in to your account)
In practice:
GET /api/v1/payments/charges/{charge_id}- Get charge detailsGET /api/v1/payments/payins- List all charges/payinsGET /api/v1/payments/payins/{charge_id}- Get payin details (same as getting charge)
Recommendation: Use "payin" when talking about business concepts, "charge" when referring to technical implementation.
Checkout vs Whitelabel Checkout
When to Use Standard Checkout
Use POST /api/v1/payments/checkouts when:
- You want the simplest integration
- You're okay redirecting to SyncPay's hosted page
- You don't need full UI control
- You want SyncPay to handle payment method selection
- Quick integration is priority
Flow:
- Create checkout → Get URL → Redirect customer → Customer completes → Webhook notification
When to Use Whitelabel Checkout
Use POST /api/v1/payments/whitelabel when:
- You want to build custom payment UI
- You're building mobile apps with native experiences
- You want to embed payments in your app (no redirect)
- You need full control over the payment flow
- You're comfortable with more complex integration
Flow:
- Create quote → Show quote to customer → Collect payment details → Create whitelabel checkout → Display payment instructions
Important: Whitelabel checkout requires a valid quote (standard checkout doesn't).
Quote Behavior
Quote Expiration
Quotes expire after 30 secs. This is hardcoded and cannot be changed.
Impact:
- If using whitelabel checkout, you must create the checkout within 30 seconds of generating the quote
- If quote expires, you'll get a
400 Bad Requestwith message"Quote expired or not found. Please get a new quote." - Solution: Generate a fresh quote
Why 30 seconds?
- Exchange rates change frequently
- Fees may change
- Ensures customers see accurate, up-to-date pricing
Quote Locking
When you create a quote, the following are locked for 10 minutes:
- Exchange rate
- Fees
- Total amount customer pays
- Gateway/provider selection
This means: Even if exchange rates change globally, your customer pays the quoted amount during the quote's lifetime.
Payment Method Availability
Enabled Payment Methods
Not all payment methods are available to all merchants:
- New merchants: Start with basic methods (bank transfer, mobile money)
- Verified merchants: Unlock card payments and additional methods
- Region-specific: Some methods only work in certain countries
Checking What's Available
To see what payment methods your organization has enabled:
# Get your organization details
curl https://api.usesyncpay.com/api/v1/organizations/me \
-H "Authorization: Bearer sk_live_..."
# Check "enabled_payment_methods" field
Currency Considerations
Local Pricing Rules
Local pricing can ONLY be used with USD as base currency:
// VALID
{
"pricing": {
"base_currency": "USD",
"amount": "50.00",
"local_pricing": {
"NGN": "75000.00"
}
}
}
// INVALID
{
"pricing": {
"base_currency": "NGN", // Not USD!
"amount": "75000.00",
"local_pricing": {
"GHS": "620.00"
}
}
}
Reason: Local pricing is designed for global USD-based merchants who want to set region-specific prices. Non-USD base currencies are region-specific by nature.
Currency-Specific Precision
Different currencies have different decimal precision:
| Currency Type | Decimals | Example |
|---|---|---|
| Most fiat (USD, NGN, GHS) | 2 | "50.00" |
| Crypto (USDT, BTC) | 2-8 | "50.00" or "0.00123456" |
| Zero-decimal (future) | 0 | "5000" |
Best practice: Always use string format for amounts to preserve precision.
Settlement Currency vs Payment Currency
Important distinction:
- Payment currency: What the customer pays in
- Settlement currency: What you receive in your account
Current behavior:
- Settlement currency = Payment currency
- If customer pays NGN 75,000, you receive NGN 75,000 (minus fees)
Future enhancement (coming soon):
- You'll be able to convert settlement to a different currency
- Example: Customer pays NGN 75,000 → You receive USD $50
Fee Handling
Fee Deduction
Fees are automatically deducted from the payment amount:
Settlement Amount = Payment Amount - Fees
Example:
- Customer pays: NGN 75,000
- Total fees: NGN 750
- You receive: NGN 74,250
Fee Transparency
When creating quotes, fees are shown transparently:
{
"fees": {
"total_fee": "750.00",
"fee_breakdown": {
"platform_fee": "500.00",
"gateway_fee": "250.00"
}
}
}
However, the amount field already includes fees:
amount: What customer sees and pays (inclusive of all fees)settlement_amount: What you receive (after fees deducted)
Checkout Expiration
Default Behavior
- Standard checkout: Expires in 60 minutes (default)
- Can be customized:
expires_in_minutes(1-1440) - Whitelabel checkout: Uses same expiration
What Happens After Expiration
- Checkout status →
EXPIRED - Checkout URL becomes invalid (returns error page)
- If customer paid but checkout expired, payment may still process (edge case)
- You'll receive a webhook with final status
Recommendation:
- Short expiration (15-30 min) for time-sensitive offers
- Longer expiration (24 hours) for invoice-style payments
- Monitor expiration events via webhooks
Metadata Limitations
Size and Key Limits
{
"metadata": {
// Maximum 20 keys
// Maximum 10KB total size
// Keys and values must be strings
}
}
What to Store in Metadata
Good uses:
- Order IDs
- Customer IDs
- Product SKUs
- Campaign tags
- Internal reference numbers
Avoid:
- Sensitive data (passwords, full card numbers)
- Large objects (user profiles, order details)
- Binary data
Why?
- Metadata is returned in webhooks
- Helps you reconcile payments
- Used for analytics and reporting
Idempotency
Current State
- Create Checkout: No built-in idempotency support
- Create Whitelabel Checkout: No built-in idempotency support
- Create Quote: No idempotency (quotes are short-lived anyway)
Best Practices
To prevent duplicate checkouts:
- Generate unique identifier in your system
- Store it in metadata
- Check for duplicates before creating checkout
async function createCheckoutIdempotent(orderData) {
const idempotencyKey = orderData.order_id;
// Check if checkout already exists for this order
const existing = await db.checkouts.findOne({
metadata: { order_id: idempotencyKey }
});
if (existing) {
return existing;
}
// Create new checkout
return await createCheckout({
...orderData,
metadata: {
order_id: idempotencyKey
}
});
}
Webhook Reliability
Best Practice: Combine Polling and Webhooks
Don't rely on webhooks alone for critical payments:
- Create checkout/payment
- Start polling the charge status endpoint
- Listen for webhooks simultaneously
- Whichever completes first wins
Why?
- Webhooks can fail (network issues, server downtime)
- Polling ensures you eventually get status
- Combined approach = most reliable
See Webhook Documentation for setup.
Rate Limits
Standard Tier
- 100 requests per minute per API key
- Applies to all endpoints
- Exceeded limit →
429 Too Many Requests
Strategies for High Volume
If you hit rate limits:
- Implement exponential backoff
- Cache results (especially for list endpoints)
- Use webhooks instead of polling
- Contact support for increased limits (available for high-volume merchants)
Test Mode vs Live Mode
Data Separation
Test and live modes are completely isolated:
- Test checkouts don't appear in live mode
- Test charges don't affect live balances
- Test webhooks go to test webhook URLs only
Test Mode Limitations
In test mode:
- No real money moves
- Some payment providers return simulated responses
- Exchange rates may be simulated or slightly delayed
- All features work the same as live mode
Transitioning to Live Mode
To go live:
- Complete business verification in dashboard
- Wait for approval (1-3 business days)
- Generate live API key (
sk_live_...) - Replace test key in production environment
- Test with small transaction first
Common Pitfalls
1. Using Number Instead of String for Amounts
Wrong:
{
"pricing": {
"base_currency": "USD",
"amount": 50.00 // Number!
}
}
Correct:
{
"pricing": {
"base_currency": "USD",
"amount": "50.00" // String!
}
}
Why: Strings preserve decimal precision and avoid floating-point errors.
2. Not Handling Quote Expiration
Whitelabel checkout requires valid quote. Always:
- Check quote
expires_attimestamp (quotes expire in 30 seconds) - If expired or close to expiring, generate new quote immediately
- Handle
400 Quote expirederrors gracefully
3. Polling Forever
Don't poll charge status indefinitely:
- Set timeout (10-15 minutes recommended)
- Use exponential backoff
- Fall back to webhooks if available
4. Hardcoding Payment Methods
Payment methods can change. Always:
- Call
GET /api/v1/payments/payment-methodsdynamically - Don't hardcode method IDs or currencies in your UI
- Check for new methods periodically
5. Ignoring Settlement Amount
The amount field is what the customer paid, but settlement_amount is what you actually receive (after fees).
Always use settlement_amount for:
- Revenue calculations
- Financial reporting
- Accounting reconciliation
Deprecated Features
Currently, there are no deprecated endpoints in the Payments API. All documented endpoints are actively supported and maintained.
Migration Notes
If you're migrating from an older integration or another payment provider:
Key Differences from Other Providers
| Feature | SyncPay | Stripe | Flutterwave |
|---|---|---|---|
| Checkout flow | Hosted + Whitelabel | Checkout Sessions | Inline + Standard |
| Multi-currency | Built-in | Limited | Regional |
| African focus | Strong | Limited | Strong |
| Crypto support | Yes | No | Limited |
Getting Help
When You're Stuck
- Check this notes file for clarifications
- Review individual endpoint docs for detailed specs
- Test in test mode to safely experiment
- Contact support with your organization ID (never share your API key!)
Support Channels
- Email: support@usesyncpay.com
- Dashboard: Live chat available (business hours)
- Documentation: https://docs.usesyncpay.com
Future Enhancements
Features currently in development:
- Idempotency keys for checkout creation
- Currency conversion for settlements
- Timestamp-based filtering for list endpoints
- Bulk operations API for high-volume merchants
- Additional payment methods (region-dependent)
Check the changelog or contact support for updates.