BeInfi Blog
Developer Guide: Integrate BeInfi Payments via API
Back to blog
API Developer Webhooks Integration Payments

Developer Guide: Integrate BeInfi Payments via API

B
BeInfi Team
| | 8 min read

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

  1. Log into your BeInfi dashboard
  2. Navigate to Settings > API Keys
  3. Click Generate New Key
  4. Choose the key permissions (read-only, write, or full access)
  5. Copy the key immediately — it won’t be shown again

Key Types

Key TypeUse CasePermissions
Secret KeyServer-side operationsFull API access
Public KeyClient-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

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

  1. Go to Settings > Webhooks in your dashboard
  2. Click Add Endpoint
  3. Enter your endpoint URL (must be HTTPS)
  4. Select the events you want to receive
  5. Copy the webhook signing secret

Webhook Event Types

EventDescriptionWhen It Fires
payment.createdA new payment was initiatedCustomer starts checkout
payment.completedPayment was confirmedFunds received successfully
payment.failedPayment attempt failedCard declined, PIX expired, etc.
payment.expiredPayment link expiredPast the expires_at timestamp
payment.refundedA refund was processedManual or API-triggered refund
subscription.createdNew subscription startedFirst payment confirmed
subscription.renewedSubscription renewedRecurring payment succeeded
subscription.cancelledSubscription cancelledCustomer 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 CodeMeaningAction
200SuccessProcess the response
400Bad RequestCheck your request body
401UnauthorizedVerify your API key
404Not FoundCheck the resource ID
422Validation ErrorCheck field requirements
429Rate LimitedBack off and retry
500Server ErrorRetry 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:

PlanRate Limit
Free60 requests/minute
Pro300 requests/minute
EnterpriseCustom 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.