Forgedocs
Guías de Integración

PIX Cash-Out (Pago)

Descripción General

El endpoint de PIX Cash-Out le permite realizar pagos PIX instantáneos a cualquier clave PIX válida (CPF, CNPJ, teléfono, email o clave aleatoria). El pago se procesa en tiempo real y el monto se debita de su cuenta inmediatamente.

Para pagos vía QR Code PIX (escaneo o copiar y pegar), use el endpoint dedicado Cash-Out vía QR Code. Este endpoint es exclusivamente para pagos por clave PIX.

Este endpoint requiere un Bearer token válido. Consulte la documentación de autenticación para más detalles.

Características

  • Pagos instantáneos 24/7
  • Soporte para todos los tipos de clave PIX
  • Validación automática de datos del destinatario
  • Identificación única vía externalId
  • Descripción personalizable para el destinatario
  • Verificación automática de saldo

Endpoint

POST /api/pix/cash-out

Realiza un pago PIX.

Encabezados Requeridos

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

Cuerpo de la Solicitud

{
  "value": 250.50,
  "details": {
    "key": "12345678901",
    "keyType": "DOCUMENT",
    "name": "Ana Costa",
    "document": "12345678901"
  },
  "externalId": "PAYMENT-987654-20240119",
  "description": "Pagamento de fornecedor"
}

Solicitud

curl -X POST https://api.gateway.goforge.com.br/api/pix/cash-out \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "value": 250.50,
    "details": {
      "key": "12345678901",
      "keyType": "DOCUMENT",
      "name": "Ana Costa",
      "document": "12345678901"
    },
    "externalId": "PAYMENT-987654-20240119",
    "description": "Pagamento de fornecedor"
  }'

Respuesta (201 Created)

{
  "transactionId": "9876",
  "externalId": "PAYMENT-987654-20240119",
  "status": "PENDING",
  "generateTime": "2024-01-19T15:45:00.000Z"
}

Parámetros de la Solicitud

valuenumberobrigatorio

Monto del pago en BRL (Reales brasileños). Debe tener como máximo 2 decimales.

Mínimo: 0.01

Ejemplo: 250.50

detailsobjectobrigatorio

Información de la clave PIX de destino.

details.keystringobrigatorio

Clave PIX de destino.

Formatos aceptados:

  • CPF: 12345678901 (11 dígitos)
  • CNPJ: 12345678000199 (14 dígitos)
  • Email: usuario@exemplo.com
  • Teléfono: 5511999999999 (con código de país y área)
  • Clave aleatoria: formato UUID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
details.keyTypestringobrigatorio

Tipo de clave PIX.

Valores aceptados:

  • DOCUMENT - CPF o CNPJ
  • EMAIL - Dirección de email
  • PHONE - Número de teléfono
  • RANDOM - Clave aleatoria (UUID)

Ejemplo: "DOCUMENT"

details.namestringobrigatorio

Nombre completo del titular de la clave PIX de destino.

Validación: El nombre debe coincidir con el registrado en la clave PIX

Ejemplo: "Ana Costa"

details.documentstringobrigatorio

CPF o CNPJ del titular (solo números).

CPF: 11 dígitos

CNPJ: 14 dígitos

Validación: El documento debe coincidir con el registrado en la clave PIX

Ejemplo: "12345678901"

externalIdstringobrigatorio

Identificador externo único de la transacción.

Máximo: 255 caracteres

Recomendación: Use un formato que garantice unicidad

Ejemplo: "PAYMENT-987654-20240119-154500"

descriptionstring

Descripción del pago que aparecerá en el extracto del destinatario.

Máximo: 140 caracteres

Predeterminado: Vacío

Ejemplo: "Pagamento de fornecedor - Nota Fiscal 12345"

Estructura de la Respuesta

transactionIdstringsempre presente

ID interno de la transacción generado por Avista.

Ejemplo: "9876"

externalIdstringsempre presente

ID externo proporcionado en la solicitud (mismo valor que la entrada).

Ejemplo: "PAYMENT-987654-20240119"

statusstringsempre presente

Estado actual de la transacción.

Valores posibles:

  • PENDING: Pago en proceso
  • CONFIRMED: Pago confirmado y completado
  • ERROR: Error de procesamiento

Ejemplo: "PENDING"

Nota: La mayoría de los pagos PIX se confirman en pocos segundos

generateTimestringsempre presente

Fecha y hora de creación del pago (ISO 8601 UTC).

Ejemplo: "2024-01-19T15:45:00.000Z"

Ejemplos de Implementación

Node.js / TypeScript

import axios from 'axios';

interface CashOutRequest {
  value: number;
  details: {
    key: string;
    keyType: 'DOCUMENT' | 'EMAIL' | 'PHONE' | 'RANDOM';
    name: string;
    document: string;
  };
  externalId: string;
  description?: string;
}

interface CashOutResponse {
  transactionId: string;
  externalId: string;
  status: 'PENDING' | 'CONFIRMED' | 'ERROR';
  generateTime: string;
}

async function sendPixPayment(
  token: string,
  recipientKey: string,
  recipientKeyType: 'DOCUMENT' | 'EMAIL' | 'PHONE' | 'RANDOM',
  recipientName: string,
  recipientDocument: string,
  amount: number,
  description?: string
): Promise<CashOutResponse> {
  const payload: CashOutRequest = {
    value: amount,
    details: {
      key: recipientKey,
      keyType: recipientKeyType,
      name: recipientName,
      document: recipientDocument
    },
    externalId: `PAY-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
    description: description || `Pagamento PIX de R$ ${amount.toFixed(2)}`
  };

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

    console.log('PIX payment initiated successfully!');
    console.log(`Transaction ID: ${response.data.transactionId}`);
    console.log(`Status: ${response.data.status}`);
    console.log(`Amount: R$ ${amount.toFixed(2)}`);
    console.log(`Recipient: ${recipientName}`);

    return response.data;
  } catch (error) {
    if (axios.isAxiosError(error)) {
      const errorData = error.response?.data;
      console.error('Error making payment:', errorData);

      // Handle specific errors
      if (error.response?.status === 400) {
        if (errorData?.message?.includes('saldo insuficiente')) {
          throw new Error('Insufficient balance to make the payment');
        }
        throw new Error('Invalid data: ' + errorData?.message);
      }

      throw new Error(errorData?.message || 'Error making PIX payment');
    }
    throw error;
  }
}

// Usage - Payment by CPF
sendPixPayment(
  'your_token_here',
  '12345678901',
  'DOCUMENT',
  'Ana Costa',
  '12345678901',
  250.50,
  'Pagamento de fornecedor'
);

// Usage - Payment by Email
sendPixPayment(
  'your_token_here',
  'ana.costa@email.com',
  'EMAIL',
  'Ana Costa',
  '12345678901',
  100.00,
  'Reembolso'
);

// Usage - Payment by Phone
sendPixPayment(
  'your_token_here',
  '5511999999999',
  'PHONE',
  'Ana Costa',
  '12345678901',
  50.00
);

Python

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

def send_pix_payment(
    token: str,
    recipient_key: str,
    recipient_key_type: str,
    recipient_name: str,
    recipient_document: str,
    amount: float,
    description: Optional[str] = None
) -> Dict:
    """
    Send a PIX payment

    Args:
        token: Valid Bearer token
        recipient_key: Recipient's PIX key
        recipient_key_type: Key type (DOCUMENT, EMAIL, PHONE, RANDOM)
        recipient_name: Recipient's name
        recipient_document: Recipient's CPF or CNPJ
        amount: Amount in BRL
        description: Payment description (optional)

    Returns:
        Initiated payment data
    """
    url = 'https://api.gateway.goforge.com.br/api/pix/cash-out'

    payload = {
        'value': round(amount, 2),
        'details': {
            'key': recipient_key,
            'keyType': recipient_key_type,
            'name': recipient_name,
            'document': recipient_document
        },
        'externalId': f'PAY-{int(datetime.now().timestamp())}-{uuid.uuid4().hex[:8]}',
        'description': description or f'Pagamento PIX de R$ {amount:.2f}'
    }

    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 payment initiated successfully!')
        print(f"Transaction ID: {data['transactionId']}")
        print(f"Status: {data['status']}")
        print(f"Amount: R$ {amount:.2f}")
        print(f"Recipient: {recipient_name}")

        return data

    except requests.exceptions.HTTPError as e:
        error_data = e.response.json() if e.response else {}

        # Handle specific errors
        if e.response.status_code == 400:
            if 'saldo insuficiente' in error_data.get('message', '').lower():
                raise Exception('Insufficient balance to make the payment')
            raise Exception(f"Invalid data: {error_data.get('message')}")

        raise Exception(f"Error making payment: {error_data.get('message', str(e))}")

# Usage
token = 'your_token_here'

# Payment by CPF
payment = send_pix_payment(
    token=token,
    recipient_key='12345678901',
    recipient_key_type='DOCUMENT',
    recipient_name='Ana Costa',
    recipient_document='12345678901',
    amount=250.50,
    description='Pagamento de fornecedor'
)

PHP

<?php

function sendPixPayment(
    string $token,
    string $recipientKey,
    string $recipientKeyType,
    string $recipientName,
    string $recipientDocument,
    float $amount,
    ?string $description = null
): array {
    $url = 'https://api.gateway.goforge.com.br/api/pix/cash-out';

    $payload = [
        'value' => round($amount, 2),
        'details' => [
            'key' => $recipientKey,
            'keyType' => $recipientKeyType,
            'name' => $recipientName,
            'document' => $recipientDocument
        ],
        'externalId' => 'PAY-' . time() . '-' . bin2hex(random_bytes(4)),
        'description' => $description ?? "Pagamento PIX de R$ " . number_format($amount, 2, ',', '.')
    ];

    $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) {
        $errorData = json_decode($response, true);
        $errorMessage = $errorData['message'] ?? "HTTP $httpCode";

        if ($httpCode === 400 && stripos($errorMessage, 'saldo insuficiente') !== false) {
            throw new Exception('Insufficient balance to make the payment');
        }

        throw new Exception("Error making payment: $errorMessage");
    }

    $data = json_decode($response, true);

    echo "PIX payment initiated successfully!" . PHP_EOL;
    echo "Transaction ID: {$data['transactionId']}" . PHP_EOL;
    echo "Status: {$data['status']}" . PHP_EOL;
    echo "Amount: R$ " . number_format($amount, 2, ',', '.') . PHP_EOL;
    echo "Recipient: $recipientName" . PHP_EOL;

    return $data;
}

// Usage
$token = 'your_token_here';
$payment = sendPixPayment(
    $token,
    '12345678901',
    'DOCUMENT',
    'Ana Costa',
    '12345678901',
    250.50,
    'Pagamento de fornecedor'
);

Validación de Clave PIX

Antes de enviar un pago, valide el formato de la clave PIX:

function validatePixKey(key: string, keyType: string): boolean {
  switch (keyType) {
    case 'DOCUMENT':
      // CPF: 11 digits or CNPJ: 14 digits
      return /^\d{11}$|^\d{14}$/.test(key);

    case 'EMAIL':
      return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(key);

    case 'PHONE':
      // Format: +5511999999999 (country code + area code + number)
      return /^55\d{10,11}$/.test(key);

    case 'RANDOM':
      // UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
      return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(key);

    default:
      return false;
  }
}

Verificación de Saldo

Siempre verifique el saldo antes de realizar pagos para evitar errores 400.

async function safePayment(
  token: string,
  amount: number,
  recipient: RecipientData
) {
  // Query balance
  const balance = await getBalance(token);

  // Check if there is sufficient balance
  if (balance.netBalance < amount) {
    throw new Error(
      `Insufficient balance. Available: R$ ${balance.netBalance.toFixed(2)} | ` +
      `Required: R$ ${amount.toFixed(2)}`
    );
  }

  // Proceed with payment
  return await sendPixPayment(token, ...recipient, amount);
}

Monitoreo de Estado

Para rastrear la confirmación del pago:

async function monitorPaymentStatus(transactionId, timeout = 60000) {
  const startTime = Date.now();

  while (Date.now() - startTime < timeout) {
    const status = await checkTransactionStatus(transactionId);

    if (status === 'CONFIRMED') {
      console.log('Payment confirmed!');
      return true;
    }

    if (status === 'ERROR') {
      throw new Error('Payment failed');
    }

    // Wait 2 seconds before checking again
    await new Promise(resolve => setTimeout(resolve, 2000));
  }

  throw new Error('Timeout: Payment not confirmed within expected time');
}

Códigos de Respuesta

CódigoDescripciónSignificado
201Pago IniciadoTransferencia PIX iniciada exitosamente
400Saldo InsuficienteSaldo insuficiente para completar la transacción
400Datos InválidosVerifique los campos requeridos y formatos
401Token InválidoToken no proporcionado, expirado o inválido

Consulte la Referencia de la API para detalles completos de los campos de respuesta.

Mejores Prácticas

Notas Importantes

  • Monto mínimo: R$ 0.01

Próximos Pasos

En esta página