Safira Paydocs
Integration Guides

PIX Cash-In (Receiving)

Overview

The PIX Cash-In endpoint allows you to generate dynamic PIX charges to receive payments. Each charge generates a unique QR Code and a PIX code (Copy and Paste) that your customers can use to make the payment.

This endpoint requires a valid Bearer token. See the authentication documentation for more details.

Features

  • Dynamic QR Code generation
  • PIX code in EMV format (Copy and Paste)
  • Configurable expiration period (5 minutes to 7 days)
  • Unique identification via externalId
  • Customizable additional information
  • Automatic CPF/CNPJ validation
  • Payment split: automatic division among multiple recipients

Endpoint

POST /api/pix/cash-in

Generates a new PIX charge.

Required Headers

Authorization: Bearer {token}
Content-Type: application/json

Request Body

{
  "transaction": {
    "value": 150.00,
    "description": "Payment for order #12345",
    "expirationTime": 86400,
    "externalId": "ORDER-12345-20240119",
    "generateQrCode": true
  },
  "payer": {
    "fullName": "Carlos Oliveira",
    "document": "12345678901"
  },
  "additionalInfo": {
    "orderId": "12345",
    "storeName": "Tech Solutions",
    "productCategory": "Electronics"
  },
  "splits": [
    {
      "pixKey": "supplier@email.com",
      "pixKeyType": "EMAIL",
      "name": "Supplier Ltd",
      "document": "12345678000199",
      "type": "PERCENTAGE",
      "value": 10,
      "immediate": false
    }
  ]
}

Request

curl -X POST https://api.safirapay.com/api/pix/cash-in \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "transaction": {
      "value": 150.00,
      "description": "Payment for order #12345",
      "expirationTime": 86400,
      "externalId": "ORDER-12345-20240119",
      "generateQrCode": true
    },
    "payer": {
      "fullName": "Carlos Oliveira",
      "document": "12345678901"
    },
    "additionalInfo": {
      "orderId": "12345"
    },
    "splits": [
      {
        "pixKey": "supplier@email.com",
        "pixKeyType": "EMAIL",
        "name": "Supplier Ltd",
        "document": "12345678000199",
        "type": "PERCENTAGE",
        "value": 70,
        "immediate": false
      }
    ]
  }'

The splits field is optional. See the Payment Split guide for complete details on types, value formats, and frequencies.

Response (201 Created)

{
  "transactionId": "7845",
  "correlationId": "550e8400-e29b-41d4-a716-446655440000",
  "externalId": "ORDER-12345-20240119",
  "status": "PENDING",
  "pixCode": "00020126580014br.gov.bcb.pix0136550e8400-e29b-41d4-a716-4466554400005204000053039865802BR5916Tech Solutions Ltda6009SAO PAULO62070503***63041D3D",
  "generateTime": "2024-01-19T14:30:00.000Z",
  "expirationDate": "2024-01-20T14:30:00.000Z",
  "qrCodeImage": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51..."
}

The qrCodeImage field is returned only when generateQrCode: true is sent in the request. The value is a Base64-encoded PNG image of the QR Code in Data URL format.

Request Parameters

Transaction Object

transaction.valuenumberobrigatorio

Transaction value in Brazilian Reais (BRL). Must have at most 2 decimal places.

Minimum: 0.01

Example: 150.00

transaction.descriptionstringobrigatorio

Transaction description that will appear on the payer's statement.

Maximum: 140 characters

Example: "Payment for order #12345"

transaction.expirationTimenumber

Expiration time in seconds.

Minimum: 300 (5 minutes)

Maximum: 604800 (7 days)

Default: 86400 (24 hours)

transaction.externalIdstringobrigatorio

Unique external identifier for the transaction. Use it to correlate with your system.

Maximum: 255 characters

Recommendation: Use a format that includes date/time to ensure uniqueness

Example: "ORDER-12345-20240119-143000"

transaction.generateQrCodeboolean

Whether to generate the QR Code in Base64.

Default: false

Recommendation: Use true to display the QR Code to the user

Payer Object

payer.fullNamestringobrigatorio

Full name of the payer.

Example: "Carlos Oliveira"

payer.documentstringobrigatorio

CPF or CNPJ of the payer (numbers only).

CPF: 11 digits

CNPJ: 14 digits

Example: "12345678901" or "12345678000199"

Additional Info Object

additionalInfoobject

Additional information in key-value format (string:string).

Maximum: 10 keys

Example:

{
  "orderId": "12345",
  "customerId": "67890",
  "storeName": "Tech Solutions"
}

Splits Array (Optional)

splitsarray

List of recipients for automatic division of the received payment. When the PIX-IN is confirmed, the value is divided and automatically sent to each recipient via PIX.

Maximum: 10 recipients per transaction

splits[].pixKeystringobrigatorio

PIX key of the split recipient.

Maximum: 255 characters

Example: "supplier@email.com"

splits[].pixKeyTypestringobrigatorio

PIX key type of the recipient.

Possible values: EMAIL, PHONE, CPF, CNPJ, RANDOM

Example: "EMAIL"

splits[].namestringobrigatorio

Full name of the recipient.

Maximum: 255 characters

Example: "Supplier Ltd"

splits[].documentstringobrigatorio

CPF or CNPJ of the recipient (digits only).

CPF: 11 digits | CNPJ: 14 digits

Example: "12345678000199"

splits[].typestringobrigatorio

Split type: fixed value or percentage.

Possible values:

  • FIXED -- Fixed value in BRL (e.g.: 10.00 = R$ 10.00)
  • PERCENTAGE -- Direct percentage (e.g.: 10 = 10%)

Example: "PERCENTAGE"

splits[].valuenumberobrigatorio

Split value according to the type:

  • FIXED: Value in BRL with up to 2 decimal places. 10.50 = R$ 10.50
  • PERCENTAGE: Direct percentage. 10 = 10%, 25.5 = 25.5%

Minimum: 0.01

Example: 10 (10% for PERCENTAGE) or 10.00 (R$ 10.00 for FIXED)

splits[].immediateboolean

If true, the split is executed immediately after PIX-IN confirmation, ignoring the frequency configured on the account.

Default: false

The sum of splits (fixed values + percentages of the gross value) plus fees cannot exceed the transaction value. If it does, the API will return error 400.

Response Structure

transactionIdstringsempre presente

Internal transaction ID generated by Avista.

Example: "7845"

correlationIdstringsempre presente

UUID for tracking and correlating the transaction.

Example: "550e8400-e29b-41d4-a716-446655440000"

externalIdstringsempre presente

External ID provided in the request (same value as input).

Example: "ORDER-12345-20240119"

statusstringsempre presente

Current transaction status.

Possible values:

  • PENDING: Awaiting payment
  • CONFIRMED: Payment confirmed
  • ERROR: Processing error

Example: "PENDING"

pixCodestringsempre presente

PIX code in EMV format (Copy and Paste).

Example: "00020126580014br.gov.bcb.pix..."

generateTimestringsempre presente

Date and time of charge generation (ISO 8601 UTC).

Example: "2024-01-19T14:30:00.000Z"

expirationDatestringsempre presente

Date and time of charge expiration (ISO 8601 UTC).

Example: "2024-01-20T14:30:00.000Z"

qrCodeImagestring

Base64 QR Code in Data URL format. Returned only when generateQrCode: true in the request.

Format: data:image/png;base64,{base64_encoded_image}

Example: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51..."

Usage: Can be displayed directly in an HTML <img> tag or decoded to save as a file.

Implementation Examples

Node.js / TypeScript

import axios from 'axios';

interface CashInRequest {
  transaction: {
    value: number;
    description: string;
    expirationTime?: number;
    externalId: string;
    generateQrCode?: boolean;
  };
  payer: {
    fullName: string;
    document: string;
  };
  additionalInfo?: Record<string, string>;
}

interface CashInResponse {
  transactionId: string;
  correlationId: string;
  externalId: string;
  status: 'PENDING' | 'CONFIRMED' | 'ERROR';
  pixCode: string;
  generateTime: string;
  expirationDate: string;
  qrCodeImage?: string; // Present only when generateQrCode: true
}

async function createPixCharge(
  token: string,
  orderId: string,
  amount: number,
  customerName: string,
  customerDocument: string
): Promise<CashInResponse> {
  const payload: CashInRequest = {
    transaction: {
      value: amount,
      description: `Payment for order ${orderId}`,
      expirationTime: 3600, // 1 hour
      externalId: `ORDER-${orderId}-${Date.now()}`,
      generateQrCode: true
    },
    payer: {
      fullName: customerName,
      document: customerDocument
    },
    additionalInfo: {
      orderId: orderId,
      timestamp: new Date().toISOString()
    }
  };

  try {
    const response = await axios.post<CashInResponse>(
      'https://api.safirapay.com/api/pix/cash-in',
      payload,
      {
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      }
    );

    console.log('PIX charge generated successfully!');
    console.log(`Transaction ID: ${response.data.transactionId}`);
    console.log(`PIX Code: ${response.data.pixCode}`);
    console.log(`Expires at: ${new Date(response.data.expirationDate).toLocaleString('pt-BR')}`);
    if (response.data.qrCodeImage) {
      console.log('QR Code Image available for display');
    }

    return response.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      console.error('Error generating charge:', error.response?.data);
      throw new Error(error.response?.data?.message || 'Error generating PIX charge');
    }
    throw error;
  }
}

// Usage
const token = 'your_token_here';
createPixCharge(token, '12345', 150.00, 'Carlos Oliveira', '12345678901');

Python

import requests
from datetime import datetime, timedelta
from typing import Dict, Optional

def create_pix_charge(
    token: str,
    order_id: str,
    amount: float,
    customer_name: str,
    customer_document: str,
    expiration_hours: int = 1,
    additional_info: Optional[Dict[str, str]] = None
) -> Dict:
    """
    Generate a PIX charge

    Args:
        token: Valid Bearer token
        order_id: Order ID
        amount: Value in BRL
        customer_name: Customer name
        customer_document: CPF or CNPJ (numbers only)
        expiration_hours: Hours until expiration (default: 1)
        additional_info: Additional information

    Returns:
        Generated charge data
    """
    url = 'https://api.safirapay.com/api/pix/cash-in'

    payload = {
        'transaction': {
            'value': round(amount, 2),
            'description': f'Payment for order {order_id}',
            'expirationTime': expiration_hours * 3600,
            'externalId': f'ORDER-{order_id}-{int(datetime.now().timestamp())}',
            'generateQrCode': True
        },
        'payer': {
            'fullName': customer_name,
            'document': customer_document
        },
        'additionalInfo': additional_info or {}
    }

    headers = {
        'Authorization': f'Bearer {token}',
        'Content-Type': 'application/json'
    }

    try:
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()

        data = response.json()

        print('PIX charge generated successfully!')
        print(f"Transaction ID: {data['transactionId']}")
        print(f"PIX Code: {data['pixCode']}")
        print(f"Status: {data['status']}")

        expiration = datetime.fromisoformat(data['expirationDate'].replace('Z', '+00:00'))
        print(f"Expires at: {expiration.strftime('%d/%m/%Y %H:%M:%S')}")

        if 'qrCodeImage' in data:
            print('QR Code Image available for display')

        return data

    except requests.exceptions.RequestException as e:
        print(f'Error generating charge: {e}')
        if hasattr(e.response, 'json'):
            print(f'Details: {e.response.json()}')
        raise

# Usage
token = 'your_token_here'
charge = create_pix_charge(
    token=token,
    order_id='12345',
    amount=150.00,
    customer_name='Carlos Oliveira',
    customer_document='12345678901',
    expiration_hours=24,
    additional_info={
        'storeName': 'Tech Solutions',
        'productCategory': 'Electronics'
    }
)

PHP

<?php

function createPixCharge(
    string $token,
    string $orderId,
    float $amount,
    string $customerName,
    string $customerDocument,
    int $expirationHours = 1
): array {
    $url = 'https://api.safirapay.com/api/pix/cash-in';

    $payload = [
        'transaction' => [
            'value' => round($amount, 2),
            'description' => "Payment for order $orderId",
            'expirationTime' => $expirationHours * 3600,
            'externalId' => "ORDER-$orderId-" . time(),
            'generateQrCode' => true
        ],
        'payer' => [
            'fullName' => $customerName,
            'document' => $customerDocument
        ],
        'additionalInfo' => [
            'orderId' => $orderId
        ]
    ];

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $token,
        'Content-Type: application/json'
    ]);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode !== 201) {
        throw new Exception("Error generating charge: HTTP $httpCode - $response");
    }

    $data = json_decode($response, true);

    echo "PIX charge generated successfully!" . PHP_EOL;
    echo "Transaction ID: {$data['transactionId']}" . PHP_EOL;
    echo "PIX Code: {$data['pixCode']}" . PHP_EOL;
    echo "Status: {$data['status']}" . PHP_EOL;
    if (isset($data['qrCodeImage'])) {
        echo "QR Code Image available for display" . PHP_EOL;
    }

    return $data;
}

// Usage
$token = 'your_token_here';
$charge = createPixCharge(
    $token,
    '12345',
    150.00,
    'Carlos Oliveira',
    '12345678901',
    24
);

Use Cases

1. E-commerce - Checkout with PIX

// E-commerce checkout integration
class PixCheckout {
  constructor(token) {
    this.token = token;
  }

  async generatePayment(order) {
    const charge = await createPixCharge(
      this.token,
      order.id,
      order.total,
      order.customer.name,
      order.customer.document
    );

    // Display QR Code on the page (using API image or generating locally)
    this.displayQrCode(charge);

    // Start polling to check payment
    this.startPaymentPolling(charge.transactionId);

    return charge;
  }

  displayQrCode(charge) {
    const qrCanvas = document.getElementById('qr-canvas');
    const qrImage = document.getElementById('qr-image');

    // Use Base64 image from API (preferred - avoids client-side processing)
    if (charge.qrCodeImage) {
      qrImage.src = charge.qrCodeImage;
      qrImage.style.display = 'block';
      qrCanvas.style.display = 'none';
    } else {
      // Fallback: generate QR Code locally using a library (e.g.: qrcode.js)
      QRCode.toCanvas(qrCanvas, charge.pixCode, {
        width: 300,
        margin: 2
      });
      qrCanvas.style.display = 'block';
      qrImage.style.display = 'none';
    }

    // Also show the PIX Copy and Paste code
    document.getElementById('pix-code').textContent = charge.pixCode;
  }

  startPaymentPolling(transactionId) {
    // Check status every 3 seconds
    const interval = setInterval(async () => {
      const status = await this.checkPaymentStatus(transactionId);

      if (status === 'CONFIRMED') {
        clearInterval(interval);
        this.onPaymentConfirmed();
      }
    }, 3000);

    // Stop after 10 minutes
    setTimeout(() => clearInterval(interval), 10 * 60 * 1000);
  }

  onPaymentConfirmed() {
    // Redirect to success page
    window.location.href = '/payment/success';
  }
}

2. POS (Point of Sale)

class PixPDV:
    """POS system with PIX charge"""

    def __init__(self, token: str):
        self.token = token

    def process_sale(self, items: list, customer: dict) -> dict:
        """Process sale and generate PIX charge"""

        # Calculate total
        total = sum(item['price'] * item['quantity'] for item in items)

        # Generate description
        description = self.generate_sale_description(items)

        # Create PIX charge (expires in 15 minutes)
        charge = create_pix_charge(
            token=self.token,
            order_id=self.generate_sale_id(),
            amount=total,
            customer_name=customer['name'],
            customer_document=customer['document'],
            expiration_hours=0.25,  # 15 minutes
            additional_info={
                'items_count': str(len(items)),
                'cashier_id': self.get_cashier_id()
            }
        )

        # Print receipt with QR Code
        self.print_receipt(charge, items, total)

        return charge

    def generate_sale_description(self, items: list) -> str:
        """Generate a summary description of the sale"""
        if len(items) == 1:
            return f"{items[0]['name']}"
        else:
            return f"{len(items)} items - {items[0]['name']} and more"

    def print_receipt(self, charge: dict, items: list, total: float):
        """Print receipt with QR Code"""
        # Implement thermal printing or generate PDF
        print("\n" + "="*50)
        print("PIX CHARGE RECEIPT")
        print("="*50)
        for item in items:
            print(f"{item['name']}: R$ {item['price']:.2f}")
        print("-"*50)
        print(f"TOTAL: R$ {total:.2f}")
        print(f"\nTransaction ID: {charge['transactionId']}")
        print(f"PIX Code:\n{charge['pixCode']}")
        print("="*50 + "\n")

3. SaaS - Subscription Billing

class SubscriptionBilling {
  constructor(private token: string) {}

  async chargeMonthlySubscription(
    subscriptionId: string,
    userId: string,
    planValue: number
  ) {
    // Fetch user data
    const user = await this.getUserData(userId);

    // Generate charge with 3-day expiration
    const charge = await createPixCharge(
      this.token,
      `SUB-${subscriptionId}-${new Date().getMonth() + 1}`,
      planValue,
      user.name,
      user.document
    );

    // Send email with payment link
    await this.sendPaymentEmail(user.email, charge);

    // Schedule reminder 1 day before expiration
    await this.scheduleReminder(user, charge, 24);

    return charge;
  }

  async sendPaymentEmail(email: string, charge: CashInResponse) {
    // Implement email sending
    const paymentLink = `https://app.example.com/payment/${charge.transactionId}`;

    await sendEmail({
      to: email,
      subject: 'Invoice available - Pay with PIX',
      html: `
        <h2>Your invoice is available</h2>
        <p>Amount: R$ ${charge.value}</p>
        <p>Due date: ${new Date(charge.expirationDate).toLocaleDateString('pt-BR')}</p>
        <p><a href="${paymentLink}">Click here to pay with PIX</a></p>
      `
    });
  }
}

Payment Monitoring

To be notified when a payment is confirmed, you can:

Configure webhooks to receive automatic notifications when the status changes.

// Webhook endpoint on your server
app.post('/webhooks/pix', (req, res) => {
  const { transactionId, status, externalId } = req.body;

  if (status === 'CONFIRMED') {
    // Process confirmed payment
    processPaymentConfirmation(externalId);
  }

  res.sendStatus(200);
});

Periodically query the transaction status.

async function monitorPayment(transactionId, maxAttempts = 200) {
  for (let i = 0; i < maxAttempts; i++) {
    const status = await checkTransactionStatus(transactionId);

    if (status === 'CONFIRMED') {
      return true;
    }

    // Wait 3 seconds before trying again
    await new Promise(resolve => setTimeout(resolve, 3000));
  }

  return false; // Timeout
}

Response Codes

CodeDescriptionMeaning
201Charge CreatedPIX charge generated successfully
400Invalid DataCheck required fields and formats
401Invalid TokenToken not provided, expired, or invalid

See the API Reference for complete details of the response fields.

Best Practices

Important Notes

Expired charges cannot be reactivated. Generate a new charge if needed.

  • Minimum value: R$ 0.01
  • Minimum expiration: 5 minutes (300 seconds)
  • Maximum expiration: 7 days (604,800 seconds)

Next Steps

On this page