Skip to Content
Pagar ProveedoresGuía de Integración

Guía de Integración para Pagar Proveedores

Esta guía te lleva a través de la implementación de pagos a proveedores en tu aplicación.

Prerequisitos

  • Credenciales API (key, secret, organizationId, merchantId)
  • Fondos en tu cuenta virtual
  • Información del proveedor lista
  • Comprensión de Cuentas Virtuales

Paso 1: Verificar Saldo de Cuenta Virtual

Siempre verifica el saldo antes de crear un payout:

async function getBalance(token, orgId, merchantId, currencySymbol) { const response = await axios.get( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/accounts/balances`, { headers: { 'Authorization': `Bearer ${token}` } } ); const balances = response.data; const balance = balances.find(b => b.currencySymbol === currencySymbol); return balance || { availableBalance: 0, currencySymbol }; } // Uso const balance = await getBalance(token, orgId, merchantId, 'COP'); console.log('Saldo disponible:', balance.availableBalance, 'COP'); // Verificar si es suficiente if (balance.availableBalance < 500000) { console.error('Saldo insuficiente para payout'); // Manejar: agregar fondos vía PAYIN o mostrar error }
def get_balance(token, org_id, merchant_id, currency_symbol): response = requests.get( f'https://api-sandbox.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/accounts/balances', headers={'Authorization': f'Bearer {token}'} ) response.raise_for_status() balances = response.json() balance = next((b for b in balances if b['currencySymbol'] == currency_symbol), None) return balance or {'availableBalance': 0, 'currencySymbol': currency_symbol} # Uso balance = get_balance(token, org_id, merchant_id, 'COP') print(f"Disponible: {balance['availableBalance']} COP")

Crítico: Si el saldo es insuficiente, la orden PAYOUT fallará. Siempre verifica el saldo primero.


Paso 2: Crear Contacto de Proveedor

Almacena información del proveedor:

async function createProviderContact(token, orgId, merchantId, providerData) { const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/contacts`, { email: providerData.email, phone: providerData.phone, fullName: providerData.fullName, countrySymbol: providerData.country, documentType: providerData.documentType, documentNumber: providerData.documentNumber, businessType: providerData.businessType // 'PERSON' o 'COMPANY' }, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } } ); return response.data; } // Uso - Proveedor empresa const provider = await createProviderContact(token, orgId, merchantId, { email: 'proveedor@ejemplo.com', phone: '+573001234567', fullName: 'Servicios ABC SAS', country: 'CO', documentType: 'NIT', // ID fiscal para empresas en Colombia documentNumber: '900123456-1', businessType: 'COMPANY' }); console.log('Contacto de proveedor creado:', provider.id);
def create_provider_contact(token, org_id, merchant_id, provider_data): response = requests.post( f'https://api-sandbox.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/contacts', json={ 'email': provider_data['email'], 'phone': provider_data.get('phone'), 'fullName': provider_data['full_name'], 'countrySymbol': provider_data['country'], 'documentType': provider_data['document_type'], 'documentNumber': provider_data['document_number'], 'businessType': provider_data['business_type'] }, headers={ 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' } ) response.raise_for_status() return response.json() # Uso provider = create_provider_contact(token, org_id, merchant_id, { 'email': 'proveedor@ejemplo.com', 'phone': '+573001234567', 'full_name': 'Servicios ABC SAS', 'country': 'CO', 'document_type': 'NIT', 'document_number': '900123456-1', 'business_type': 'COMPANY' })

Paso 3: Agregar Cuenta Bancaria del Proveedor

Vincula los detalles de cuenta bancaria del proveedor:

async function addProviderBankAccount(token, orgId, merchantId, contactId, bankData) { const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/contacts/${contactId}/accounts`, { countrySymbol: bankData.country, currencySymbol: bankData.currency, bankCode: bankData.bankCode, accountNumber: bankData.accountNumber, accountType: bankData.accountType, // 'checking' o 'savings' holderName: bankData.holderName }, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } } ); return response.data; } // Uso const bankAccount = await addProviderBankAccount(token, orgId, merchantId, provider.id, { country: 'CO', currency: 'COP', bankCode: 'BANCOLOMBIA', accountNumber: '1234567890', accountType: 'checking', holderName: 'Servicios ABC SAS' }); console.log('Cuenta bancaria agregada:', bankAccount.id);
def add_provider_bank_account(token, org_id, merchant_id, contact_id, bank_data): response = requests.post( f'https://api-sandbox.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/contacts/{contact_id}/accounts', json={ 'countrySymbol': bank_data['country'], 'currencySymbol': bank_data['currency'], 'bankCode': bank_data['bank_code'], 'accountNumber': bank_data['account_number'], 'accountType': bank_data['account_type'], 'holderName': bank_data['holder_name'] }, headers={ 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' } ) response.raise_for_status() return response.json() # Uso bank_account = add_provider_bank_account(token, org_id, merchant_id, provider['id'], { 'country': 'CO', 'currency': 'COP', 'bank_code': 'BANCOLOMBIA', 'account_number': '1234567890', 'account_type': 'checking', 'holder_name': 'Servicios ABC SAS' })

Códigos Bancarios por País

PaísBancos EjemploFormato de Código
ColombiaBANCOLOMBIA, DAVIVIENDA, BOGOTANombre de banco
BrasilBANCO_DO_BRASIL, BRADESCO, ITAUCódigo de banco
MéxicoBBVA_MEXICO, SANTANDER_MEXICOIdentificador de banco
ChileBANCO_CHILE, BCI, SANTANDER_CHILENombre de banco

Referencia completa de códigos bancarios →


Paso 4: Crear Orden PAYOUT

Crear la orden de payout:

async function createPayoutOrder(token, orgId, merchantId, payoutData) { const response = await axios.post( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders`, { type: 'PAYOUT', originCurrencySymbol: payoutData.currency, destinationCurrencySymbol: payoutData.currency, // Misma moneda amountIn: payoutData.amount, contactId: payoutData.contactId, destinationAccountId: payoutData.destinationAccountId, // ID de cuenta bancaria description: payoutData.description, externalId: payoutData.externalId // Tu referencia interna }, { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' } } ); return response.data; } // Uso const payout = await createPayoutOrder(token, orgId, merchantId, { currency: 'COP', amount: 500000, // 500,000 COP contactId: provider.id, destinationAccountId: bankAccount.id, description: 'Pago por Factura #INV-001', externalId: `payout-inv-001-${Date.now()}` }); console.log('Payout creado:', payout.id); console.log('Estado:', payout.status); // "PROCESSING"
def create_payout_order(token, org_id, merchant_id, payout_data): import time response = requests.post( f'https://api-sandbox.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/orders', json={ 'type': 'PAYOUT', 'originCurrencySymbol': payout_data['currency'], 'destinationCurrencySymbol': payout_data['currency'], 'amountIn': payout_data['amount'], 'contactId': payout_data['contact_id'], 'destinationAccountId': payout_data['destination_account_id'], 'description': payout_data['description'], 'externalId': payout_data['external_id'] }, headers={ 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' } ) response.raise_for_status() return response.json() # Uso payout = create_payout_order(token, org_id, merchant_id, { 'currency': 'COP', 'amount': 500000, 'contact_id': provider['id'], 'destination_account_id': bank_account['id'], 'description': 'Pago por Factura #INV-001', 'external_id': f'payout-inv-001-{int(time.time())}' }) print(f"Payout creado: {payout['id']}")
curl -X POST 'https://api-sandbox.koywe.com/api/v1/organizations/TU_ORG_ID/merchants/TU_MERCHANT_ID/orders' \ -H 'Authorization: Bearer TU_TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "type": "PAYOUT", "originCurrencySymbol": "COP", "destinationCurrencySymbol": "COP", "amountIn": 500000, "contactId": "cnt_provider123", "destinationAccountId": "ba_xyz789", "description": "Pago por Factura #INV-001", "externalId": "payout-inv-001-1699999999" }'

Respuesta:

{ "id": "ord_payout123", "type": "PAYOUT", "status": "PROCESSING", "amountIn": 500000, "originCurrencySymbol": "COP", "destinationCurrencySymbol": "COP", "externalId": "payout-inv-001-1699999999", "description": "Pago por Factura #INV-001", "createdAt": "2025-11-13T15:00:00Z" }

Paso 5: Monitorear Estado de Payout

Rastrea el payout vía webhooks o polling:

Vía Webhooks (Recomendado)

app.post('/webhooks/koywe', express.raw({type: 'application/json'}), async (req, res) => { // Convertir body raw a string una vez const rawBody = req.body.toString(); // Verificar firma con body string const signature = req.headers['koywe-signature']; if (!verifySignature(rawBody, signature, process.env.KOYWE_WEBHOOK_SECRET)) { return res.status(401).send('Firma inválida'); } // Parsear JSON desde string const event = JSON.parse(rawBody); switch (event.type) { case 'order.processing': console.log('Payout procesando:', event.data.orderId); // Actualizar estado interno await updatePayoutStatus(event.data.externalId, 'processing'); break; case 'order.completed': console.log('Payout completado:', event.data.orderId); // Marcar como pagado en tu sistema await markInvoiceAsPaid(event.data.externalId); await notifyProvider(event.data.externalId); break; case 'order.failed': console.log('Payout fallido:', event.data.orderId); // Manejar fallo await handlePayoutFailure(event.data.externalId, event.data.errorMessage); break; } res.status(200).send('OK'); });

Vía Polling (Alternativa)

async function waitForPayoutCompletion(token, orgId, merchantId, orderId, maxAttempts = 20) { for (let i = 0; i < maxAttempts; i++) { const order = await axios.get( `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/orders/${orderId}`, { headers: { 'Authorization': `Bearer ${token}` } } ); const status = order.data.status; console.log(`Intento ${i + 1}: Estado = ${status}`); if (status === 'COMPLETED') { console.log('✓ Payout completado exitosamente'); return order.data; } if (status === 'FAILED') { throw new Error(`Payout fallido: ${order.data.errorMessage}`); } // Esperar 5 segundos antes de verificar nuevamente await new Promise(resolve => setTimeout(resolve, 5000)); } throw new Error('Tiempo de espera agotado'); }

Ejemplo Completo de Extremo a Extremo

async function completePayoutFlow() { try { // 1. Autenticar const token = await authenticate(apiKey, secret); console.log('✓ Autenticado'); // 2. Verificar saldo const balance = await getBalance(token, orgId, merchantId, 'COP'); if (balance.availableBalance < 500000) { throw new Error('Saldo insuficiente'); } console.log(`✓ Saldo suficiente: ${balance.availableBalance} COP`); // 3. Crear/obtener contacto de proveedor const provider = await createProviderContact(token, orgId, merchantId, { email: 'proveedor@ejemplo.com', fullName: 'Servicios ABC SAS', country: 'CO', documentType: 'NIT', documentNumber: '900123456-1', businessType: 'COMPANY' }); console.log('✓ Proveedor creado:', provider.id); // 4. Agregar cuenta bancaria const bankAccount = await addProviderBankAccount( token, orgId, merchantId, provider.id, { country: 'CO', currency: 'COP', bankCode: 'BANCOLOMBIA', accountNumber: '1234567890', accountType: 'checking', holderName: 'Servicios ABC SAS' } ); console.log('✓ Cuenta bancaria agregada:', bankAccount.id); // 5. Crear payout const payout = await createPayoutOrder(token, orgId, merchantId, { currency: 'COP', amount: 500000, contactId: provider.id, destinationAccountId: bankAccount.id, description: 'Pago por Factura #INV-001', externalId: `payout-${Date.now()}` }); console.log('✓ Payout creado:', payout.id); console.log(' Estado:', payout.status); // 6. Esperar confirmación (o confiar en webhooks) console.log('Esperando completación...'); const completed = await waitForPayoutCompletion( token, orgId, merchantId, payout.id ); console.log('✓ Payout completado exitosamente!'); console.log(' ID de Orden:', completed.id); console.log(' Monto:', completed.amountIn, completed.originCurrencySymbol); return completed; } catch (error) { console.error('Error en flujo de payout:', error.message); throw error; } } // Ejecutar await completePayoutFlow();

Próximos Pasos

Last updated on