Developer Guide: Integrate BeInfi Payments via API
If you’re building an app, SaaS, or marketplace that needs payment processing, BeInfi’s API gives you everything you need. This guide covers API key management, creating payments, handling webhooks, and best practices — all with TypeScript examples you can use today.
Getting Started
Prerequisites
- A BeInfi account (sign up here)
- Node.js 18+ or any environment that supports
fetch - Basic knowledge of REST APIs and TypeScript
API Base URL
https://api.beinfi.com/v1
All requests must include authentication and use Content-Type: application/json.
API Key Management
Generating API Keys
- Log into your BeInfi dashboard
- Navigate to Settings > API Keys
- Click Generate New Key
- Choose the key permissions (read-only, write, or full access)
- Copy the key immediately — it won’t be shown again
Key Types
| Key Type | Use Case | Permissions |
|---|---|---|
| Secret Key | Server-side operations | Full API access |
| Public Key | Client-side (limited) | Read-only, payment initiation |
Security Best Practices
- Never expose secret keys in client-side code or public repositories
- Use environment variables to store keys
- Rotate keys regularly — monthly for production, after any team member leaves
- Use separate keys for development and production
// Store keys in environment variables
const API_KEY = process.env.BEINFI_SECRET_KEY;
if (!API_KEY) {
throw new Error('BEINFI_SECRET_KEY is not configured');
}
Authentication
Every API request requires a Bearer token in the Authorization header:
const headers = {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
};
Invalid or expired keys return a 401 Unauthorized response.
Creating Payments
Create a Payment Link
interface CreatePaymentRequest {
amount: number;
currency: 'BRL';
description: string;
redirect_url?: string;
metadata?: Record<string, string>;
expires_at?: string; // ISO 8601
}
interface PaymentResponse {
id: string;
status: 'pending' | 'completed' | 'failed' | 'expired';
amount: number;
currency: string;
payment_url: string;
pix_code?: string;
created_at: string;
expires_at: string | null;
}
async function createPayment(
data: CreatePaymentRequest
): Promise<PaymentResponse> {
const response = await fetch('https://api.beinfi.com/v1/payments', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Payment creation failed: ${error.message}`);
}
return response.json();
}
// Usage
const payment = await createPayment({
amount: 49.90,
currency: 'BRL',
description: 'Pro Plan - Monthly Subscription',
redirect_url: 'https://yourapp.com/success',
metadata: {
user_id: 'usr_12345',
plan: 'pro_monthly',
},
});
console.log(`Payment URL: ${payment.payment_url}`);
console.log(`PIX Code: ${payment.pix_code}`);
Check Payment Status
async function getPayment(paymentId: string): Promise<PaymentResponse> {
const response = await fetch(
`https://api.beinfi.com/v1/payments/${paymentId}`,
{
headers: {
'Authorization': `Bearer ${API_KEY}`,
},
}
);
if (!response.ok) {
throw new Error(`Failed to fetch payment: ${response.statusText}`);
}
return response.json();
}
// Poll for payment completion (or use webhooks — recommended)
const status = await getPayment('pay_abc123');
console.log(`Payment status: ${status.status}`);
List Payments
interface ListPaymentsParams {
status?: 'pending' | 'completed' | 'failed' | 'expired';
limit?: number;
offset?: number;
created_after?: string;
created_before?: string;
}
async function listPayments(
params: ListPaymentsParams = {}
): Promise<{ data: PaymentResponse[]; total: number }> {
const searchParams = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined) searchParams.set(key, String(value));
});
const response = await fetch(
`https://api.beinfi.com/v1/payments?${searchParams}`,
{
headers: {
'Authorization': `Bearer ${API_KEY}`,
},
}
);
return response.json();
}
Webhook Configuration
Webhooks let your application receive real-time notifications about payment events. This is the recommended approach instead of polling.
Setting Up Webhooks
- Go to Settings > Webhooks in your dashboard
- Click Add Endpoint
- Enter your endpoint URL (must be HTTPS)
- Select the events you want to receive
- Copy the webhook signing secret
Webhook Event Types
| Event | Description | When It Fires |
|---|---|---|
payment.created | A new payment was initiated | Customer starts checkout |
payment.completed | Payment was confirmed | Funds received successfully |
payment.failed | Payment attempt failed | Card declined, PIX expired, etc. |
payment.expired | Payment link expired | Past the expires_at timestamp |
payment.refunded | A refund was processed | Manual or API-triggered refund |
subscription.created | New subscription started | First payment confirmed |
subscription.renewed | Subscription renewed | Recurring payment succeeded |
subscription.cancelled | Subscription cancelled | Customer or merchant cancellation |
Webhook Payload Structure
interface WebhookPayload {
id: string;
event: string;
created_at: string;
data: {
payment_id: string;
amount: number;
currency: string;
status: string;
metadata: Record<string, string>;
};
}
Handling Webhooks
import { createHmac } from 'crypto';
const WEBHOOK_SECRET = process.env.BEINFI_WEBHOOK_SECRET!;
function verifyWebhookSignature(
payload: string,
signature: string
): boolean {
const expected = createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
return signature === `sha256=${expected}`;
}
// Express.js example
app.post('/webhooks/beinfi', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-beinfi-signature'] as string;
const payload = req.body.toString();
if (!verifyWebhookSignature(payload, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event: WebhookPayload = JSON.parse(payload);
switch (event.event) {
case 'payment.completed':
handlePaymentCompleted(event.data);
break;
case 'payment.failed':
handlePaymentFailed(event.data);
break;
case 'subscription.renewed':
handleSubscriptionRenewal(event.data);
break;
default:
console.log(`Unhandled event type: ${event.event}`);
}
// Always return 200 to acknowledge receipt
res.status(200).json({ received: true });
});
async function handlePaymentCompleted(data: WebhookPayload['data']) {
// Update your database
await db.orders.update({
where: { paymentId: data.payment_id },
data: { status: 'paid' },
});
// Grant access, send confirmation email, etc.
await grantAccess(data.metadata.user_id, data.metadata.plan);
await sendConfirmationEmail(data.metadata.user_id);
}
Webhook Best Practices
- Always verify signatures before processing events
- Return 200 quickly — do heavy processing asynchronously
- Handle duplicates — webhook events may be sent more than once
- Log everything — store raw webhook payloads for debugging
- Set up retry handling — BeInfi retries failed deliveries with exponential backoff
// Idempotency: prevent duplicate processing
async function processWebhook(event: WebhookPayload) {
const existing = await db.webhookEvents.findUnique({
where: { eventId: event.id },
});
if (existing) {
console.log(`Event ${event.id} already processed, skipping`);
return;
}
// Process the event
await handleEvent(event);
// Record that we processed it
await db.webhookEvents.create({
data: { eventId: event.id, processedAt: new Date() },
});
}
Error Handling
The API uses standard HTTP status codes:
| Status Code | Meaning | Action |
|---|---|---|
200 | Success | Process the response |
400 | Bad Request | Check your request body |
401 | Unauthorized | Verify your API key |
404 | Not Found | Check the resource ID |
422 | Validation Error | Check field requirements |
429 | Rate Limited | Back off and retry |
500 | Server Error | Retry with exponential backoff |
class BeInfiAPIError extends Error {
constructor(
public statusCode: number,
public errorCode: string,
message: string
) {
super(message);
this.name = 'BeInfiAPIError';
}
}
async function apiRequest<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const response = await fetch(`https://api.beinfi.com/v1${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
...options.headers,
},
});
if (!response.ok) {
const error = await response.json();
throw new BeInfiAPIError(
response.status,
error.code,
error.message
);
}
return response.json();
}
Rate Limits
The API enforces rate limits to ensure stability:
| Plan | Rate Limit |
|---|---|
| Free | 60 requests/minute |
| Pro | 300 requests/minute |
| Enterprise | Custom limits |
Rate-limited responses include headers with reset information:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 12
X-RateLimit-Reset: 1709251200
Full Integration Example
Here’s a complete Next.js API route that creates a payment and handles the webhook:
// app/api/checkout/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
const { planId, userId } = await req.json();
const plans: Record<string, { name: string; price: number }> = {
starter: { name: 'Starter Plan', price: 29.90 },
pro: { name: 'Pro Plan', price: 79.90 },
business: { name: 'Business Plan', price: 199.90 },
};
const plan = plans[planId];
if (!plan) {
return NextResponse.json(
{ error: 'Invalid plan' },
{ status: 400 }
);
}
const payment = await apiRequest<PaymentResponse>('/payments', {
method: 'POST',
body: JSON.stringify({
amount: plan.price,
currency: 'BRL',
description: `${plan.name} - Monthly`,
redirect_url: `${process.env.NEXT_PUBLIC_URL}/dashboard?payment=success`,
metadata: {
user_id: userId,
plan_id: planId,
},
}),
});
return NextResponse.json({
paymentUrl: payment.payment_url,
pixCode: payment.pix_code,
});
}
What’s Next
Once you have payments working, explore these next steps:
- Add subscription management for recurring billing
- Build a customer portal using the payments list endpoint
- Set up monitoring with webhook event logs
- Implement refund flows through the refunds API
BeInfi’s API is built for developers who want payment infrastructure that just works. Clean endpoints, predictable webhooks, and TypeScript-first design. Start building at beinfi.com.