Sir Chargly - API Integration Guide
Complete guide to integrating Sir Chargly's convenience fee platform into your application.
Table of Contents
Quick Start
1. Install the SDK
npm install @sirchargly/sdk
# or
yarn add @sirchargly/sdk
2. Set Up Environment Variables
Create a .env.local file in your project root:
# Development keys (from onboarding)
SIRCHARGLEY_PUBLISHABLE_KEY=pk_dev_sirchargly_...
SIRCHARGLEY_SECRET_KEY=sk_dev_sirchargly_...
# Production keys (when ready to go live)
# SIRCHARGLEY_PUBLISHABLE_KEY=pk_prod_sirchargly_...
# SIRCHARGLEY_SECRET_KEY=sk_prod_sirchargly_...
3. Basic Integration
import { SirChargly } from '@sirchargly/sdk';
// Initialize with publishable key
const chargly = new SirChargly(
process.env.NEXT_PUBLIC_SIRCHARGLEY_PUBLISHABLE_KEY!
);
// Create a payment with automatic fee calculation
const payment = await chargly.payments.create({
amount: 10000, // $100.00 in cents
currency: 'usd',
customer: 'cus_123',
});
console.log(payment);
// {
// id: 'pay_...',
// amount: 10000,
// convenienceFee: 320, // $3.20
// totalAmount: 10320, // $103.20
// ...
// }
Authentication
Sir Chargly uses API keys for authentication. There are two types:
Publishable Keys
Format: pk_dev_sirchargly_... or pk_prod_sirchargly_...
Usage:
// Client-side (React, Vue, etc.)
const chargly = new SirChargly('pk_dev_sirchargly_...');
Secret Keys
Format: sk_dev_sirchargly_... or sk_prod_sirchargly_...
Usage:
// Server-side (API routes, backend)
const response = await fetch('https://api.sirchargly.com/v1/charges', {
headers: {
'Authorization': `Bearer ${process.env.SIRCHARGLEY_SECRET_KEY}`,
'Content-Type': 'application/json',
},
});
Environment Detection
Keys automatically determine the environment:
pk_dev_* / sk_dev_* → Development mode (test data)pk_prod_* / sk_prod_* → Production mode (live data)API Endpoints
Base URL: https://api.sirchargly.com/v1
Calculate Fee
Estimate convenience fee for a transaction
POST /v1/estimates
Authorization: Bearer sk_dev_sirchargly_...
Content-Type: application/json
{
"amount": 10000,
"currency": "usd",
"region": "US-CA",
"cardType": "credit"
}
Response:
{
"baseAmount": 10000,
"convenienceFee": 320,
"totalAmount": 10320,
"feeBreakdown": {
"percentage": 290,
"flatFee": 30
},
"compliant": true,
"region": "US-CA"
}
Create Charge
Process a payment with convenience fee
POST /v1/charges
Authorization: Bearer sk_dev_sirchargly_...
Content-Type: application/json
{
"amount": 10000,
"currency": "usd",
"customer": "cus_123",
"description": "Order #1234",
"metadata": {
"orderId": "1234"
}
}
Response:
{
"id": "ch_sirchargly_...",
"object": "charge",
"amount": 10000,
"convenienceFee": 320,
"totalAmount": 10320,
"currency": "usd",
"customer": "cus_123",
"status": "succeeded",
"created": 1704067200,
"metadata": {
"orderId": "1234"
}
}
List Charges
Get all charges for your account
GET /v1/charges?limit=10&starting_after=ch_...
Authorization: Bearer sk_dev_sirchargly_...
Response:
{
"object": "list",
"data": [
{ /* charge object */ },
{ /* charge object */ }
],
"has_more": true,
"url": "/v1/charges"
}
Get Fee Configuration
Retrieve your current fee settings
GET /v1/fee-configs
Authorization: Bearer sk_dev_sirchargly_...
Response:
{
"percentage": 2.9,
"flatFee": 0.30,
"billingMode": "direct",
"regions": {
"US-CA": {
"maxPercentage": 4.0,
"requiresDisclosure": true
}
}
}
Update Fee Configuration
Change your fee settings
POST /v1/fee-configs
Authorization: Bearer sk_dev_sirchargly_...
Content-Type: application/json
{
"percentage": 3.0,
"flatFee": 0.35
}
Regional Compliance
Check compliance rules for a region
GET /v1/regions/US-CA
Authorization: Bearer sk_dev_sirchargly_...
Response:
{
"regionCode": "US-CA",
"country": "US",
"state": "California",
"allowedCardTypes": ["credit", "debit"],
"maxPercentage": 4.0,
"maxFlatFee": 2.0,
"requiresDisclosure": true,
"disclosureText": "A convenience fee of X% will be added to this transaction."
}
SDK Usage
Initialization
import { SirChargly } from '@sirchargly/sdk';
const chargly = new SirChargly(
process.env.NEXT_PUBLIC_SIRCHARGLEY_PUBLISHABLE_KEY!,
{
apiVersion: '2025-01',
timeout: 30000, // 30 seconds
}
);
Creating Payments
// Simple payment
const payment = await chargly.payments.create({
amount: 10000,
currency: 'usd',
customer: 'cus_123',
});
// With metadata
const payment = await chargly.payments.create({
amount: 10000,
currency: 'usd',
customer: 'cus_123',
metadata: {
orderId: '1234',
productId: 'prod_456',
},
});
// With specific region
const payment = await chargly.payments.create({
amount: 10000,
currency: 'usd',
customer: 'cus_123',
region: 'US-TX',
});
Estimating Fees
// Get fee estimate before charging
const estimate = await chargly.estimates.create({
amount: 10000,
currency: 'usd',
region: 'US-CA',
cardType: 'credit',
});
console.log(`Base: $${estimate.baseAmount / 100}`);
console.log(`Fee: $${estimate.convenienceFee / 100}`);
console.log(`Total: $${estimate.totalAmount / 100}`);
Retrieving Charges
// Get a specific charge
const charge = await chargly.charges.retrieve('ch_sirchargly_...');
// List all charges
const charges = await chargly.charges.list({
limit: 10,
});
// List with filters
const charges = await chargly.charges.list({
limit: 25,
created: {
gte: Math.floor(Date.now() / 1000) - 30 * 24 * 60 * 60, // Last 30 days
},
});
Fee Configuration
// Get current config
const config = await chargly.feeConfigs.retrieve();
// Update config
const newConfig = await chargly.feeConfigs.update({
percentage: 3.0,
flatFee: 0.35,
});
Regional Compliance
// Get region info
const region = await chargly.regions.retrieve('US-CA');
// Check if a fee structure is compliant
const isCompliant = await chargly.regions.checkCompliance({
region: 'US-CA',
percentage: 3.5,
flatFee: 0.30,
cardType: 'credit',
});
Webhooks
Sir Chargly sends webhooks for various events to keep your system in sync.
Setting Up Webhooks
https://yourdomain.com/api/webhooks/sircharglyWebhook Events
charge.succeeded
{
"id": "evt_...",
"type": "charge.succeeded",
"data": {
"object": {
"id": "ch_sirchargly_...",
"amount": 10000,
"convenienceFee": 320,
"status": "succeeded"
}
},
"created": 1704067200
}
charge.failed
{
"id": "evt_...",
"type": "charge.failed",
"data": {
"object": {
"id": "ch_sirchargly_...",
"amount": 10000,
"status": "failed",
"failureCode": "card_declined",
"failureMessage": "Your card was declined"
}
},
"created": 1704067200
}
fee_config.updated
{
"id": "evt_...",
"type": "fee_config.updated",
"data": {
"object": {
"percentage": 3.0,
"flatFee": 0.35,
"billingMode": "direct"
}
},
"created": 1704067200
}
Verifying Webhooks (Next.js App Router)
import { NextRequest, NextResponse } from 'next/server';
import { headers } from 'next/headers';
import { SirChargly } from '@sirchargly/sdk';
const webhookSecret = process.env.SIRCHARGLEY_WEBHOOK_SECRET!;
export async function POST(req: NextRequest) {
const body = await req.text();
const signature = headers().get('sirchargly-signature');
if (!signature) {
return NextResponse.json(
{ error: 'Missing signature' },
{ status: 400 }
);
}
// Verify the webhook signature
let event;
try {
event = SirChargly.webhooks.constructEvent(
body,
signature,
webhookSecret
);
} catch (err) {
return NextResponse.json(
{ error: 'Invalid signature' },
{ status: 400 }
);
}
// Handle the event
switch (event.type) {
case 'charge.succeeded':
const charge = event.data.object;
console.log('Charge succeeded:', charge.id);
// Update your database, send confirmation email, etc.
break;
case 'charge.failed':
const failedCharge = event.data.object;
console.log('Charge failed:', failedCharge.id);
// Notify customer, log for review, etc.
break;
case 'fee_config.updated':
const config = event.data.object;
console.log('Fee config updated:', config);
// Update cached config, notify admin, etc.
break;
default:
console.log('Unhandled event type:', event.type);
}
return NextResponse.json({ received: true });
}
Error Handling
Error Types
try {
const payment = await chargly.payments.create({
amount: 10000,
currency: 'usd',
});
} catch (error) {
if (error.type === 'AuthenticationError') {
// Invalid API key
console.error('Authentication failed');
} else if (error.type === 'InvalidRequestError') {
// Invalid parameters
console.error('Invalid request:', error.message);
} else if (error.type === 'APIError') {
// Server error
console.error('API error:', error.message);
} else if (error.type === 'NetworkError') {
// Network connectivity issue
console.error('Network error');
}
}
Error Responses
{
"error": {
"type": "invalid_request_error",
"message": "Amount must be at least $0.50",
"param": "amount",
"code": "amount_too_small"
}
}
Retry Logic
async function createPaymentWithRetry(
params: PaymentParams,
maxRetries = 3
) {
for (let i = 0; i < maxRetries; i++) {
try {
return await chargly.payments.create(params);
} catch (error) {
if (error.type === 'NetworkError' && i < maxRetries - 1) {
// Wait before retrying (exponential backoff)
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, i) * 1000)
);
continue;
}
throw error;
}
}
}
Testing
Test Mode
All development keys (pk_dev_*, sk_dev_*) operate in test mode:
Test Card Numbers
Successful Payments:
4242 4242 4242 4242 (Visa)
5555 5555 5555 4444 (Mastercard)
3782 822463 10005 (American Express)
Declined Payments:
4000 0000 0000 0002 (Card declined)
4000 0000 0000 9995 (Insufficient funds)
Test Scenarios
// Test successful payment
const successfulPayment = await chargly.payments.create({
amount: 10000,
currency: 'usd',
paymentMethod: {
card: {
number: '4242424242424242',
exp_month: 12,
exp_year: 2025,
cvc: '123',
},
},
});
// Test declined payment
try {
const declinedPayment = await chargly.payments.create({
amount: 10000,
currency: 'usd',
paymentMethod: {
card: {
number: '4000000000000002',
exp_month: 12,
exp_year: 2025,
cvc: '123',
},
},
});
} catch (error) {
console.log('Expected decline:', error.code); // card_declined
}
// Test regional compliance
const californiaPayment = await chargly.payments.create({
amount: 10000,
currency: 'usd',
region: 'US-CA',
});
Production Deployment
Pre-Deployment Checklist
Environment Variables
Development:
SIRCHARGLEY_PUBLISHABLE_KEY=pk_dev_sirchargly_...
SIRCHARGLEY_SECRET_KEY=sk_dev_sirchargly_...
SIRCHARGLEY_WEBHOOK_SECRET=whsec_dev_...
Production:
SIRCHARGLEY_PUBLISHABLE_KEY=pk_prod_sirchargly_...
SIRCHARGLEY_SECRET_KEY=sk_prod_sirchargly_...
SIRCHARGLEY_WEBHOOK_SECRET=whsec_prod_...
Security Best Practices
```bash
# .gitignore
.env.local
.env.production
```
```typescript
// ✅ Good
const key = process.env.SIRCHARGLEY_SECRET_KEY;
// ❌ Bad
const key = 'sk_prod_sirchargly_...';
```
```typescript
// Always verify webhook authenticity
const event = SirChargly.webhooks.constructEvent(
body,
signature,
webhookSecret
);
```
```
✅ https://yourdomain.com/api/webhooks
❌ http://yourdomain.com/api/webhooks
```
```typescript
// Prevent abuse of your endpoints
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
});
```
Monitoring
Track Key Metrics:
Set Up Alerts:
Rollback Plan
Support
Resources
Getting Help
Reporting Issues
Include the following when reporting bugs:
Examples
Complete Payment Flow
import { SirChargly } from '@sirchargly/sdk';
const chargly = new SirChargly(process.env.SIRCHARGLEY_PUBLISHABLE_KEY!);
async function processOrder(orderId: string, amount: number) {
try {
// 1. Get fee estimate
const estimate = await chargly.estimates.create({
amount,
currency: 'usd',
});
// 2. Show customer the total including fee
console.log(`Order: $${amount / 100}`);
console.log(`Convenience Fee: $${estimate.convenienceFee / 100}`);
console.log(`Total: $${estimate.totalAmount / 100}`);
// 3. Create the charge
const charge = await chargly.charges.create({
amount,
currency: 'usd',
metadata: { orderId },
});
// 4. Save charge ID to your database
await saveChargeToDatabase(orderId, charge.id);
return {
success: true,
chargeId: charge.id,
totalAmount: charge.totalAmount,
};
} catch (error) {
console.error('Payment failed:', error);
return {
success: false,
error: error.message,
};
}
}
This completes the API Integration Guide! 🚀