Koywe
On this page

Contacts & Bank Accounts

Contacts represent your customers or providers in the Koywe system, storing their information and linked bank accounts for payment operations.

What are Contacts?

A Contact is a person or business entity that you interact with through payments:

  • Customers who pay you (PAYIN)
  • Providers who you pay (PAYOUT)
  • Both in marketplace scenarios

Why Use Contacts?

Tracking

Track payment history per customer or provider

Compliance

Store KYC/compliance information (documents, tax IDs)

Simplified Payouts

Link bank accounts for easy recurring payments

Reporting

Generate reports per contact or business type


Contact Structure

Required Fields

JavaScript
{
  "firstName": "Juan",                       // First name
  "countrySymbol": "CO",                     // Country code
  "businessType": "PERSON",                  // PERSON, COMPANY, etc.
  "type": "PERSON"                           // PERSON, BUSINESS, GOVERNMENT, NGO, FOREIGN
}

Optional Fields

JavaScript
{
  "lastName": "Pérez",                       // Last name
  "email": "customer@example.com",           // Email address
  "phone": "+573001234567",                  // Phone number
  "documentType": "CED_CIU",                 // ID document type (see Document Types by Country). For "BR", a CPF or CNPJ is required: send it here or in documents[]
  "documentNumber": "1234567890",            // ID document number (required if documentType is provided)
  "taxIdType": "NIT",                        // Tax ID type (deprecated, use documentType)
  "taxIdNumber": "9001234561",               // Tax ID number (deprecated, use documentNumber)
  "addressLine1": "Calle 123",               // Street address
  "city": "Bogotá",                          // City
  "state": "Cundinamarca",                   // State / department
  "postalCode": "110111"                     // Postal code
}

Creating Contacts

Basic Contact Creation

async function createContact(token, orgId, merchantId, contactData) {
  const response = await axios.post(
    `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/contacts`,
    {
      firstName: contactData.firstName,
      lastName: contactData.lastName,               // Optional
      email: contactData.email,                     // Optional
      phone: contactData.phone,                     // Optional
      countrySymbol: contactData.countrySymbol,
      documentType: contactData.documentType,       // Optional
      documentNumber: contactData.documentNumber,   // Optional (required if documentType is provided)
      businessType: 'PERSON',                       // or 'COMPANY'
      type: 'PERSON'                                // PERSON, BUSINESS, GOVERNMENT, NGO, FOREIGN
    },
    {
      headers: { 
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    }
  );
  
  return response.data;
}
 
// Usage - Creating a customer contact
const customer = await createContact(token, orgId, merchantId, {
  firstName: 'Juan',
  lastName: 'Pérez',
  countrySymbol: 'CO',
  email: 'customer@example.com',
  phone: '+573001234567',
  documentType: 'CED_CIU',
  documentNumber: '1234567890'
});
 
console.log('Contact created:', customer.id);

Response:

JSON
{
  "id": "cnt_abc123",
  "firstName": "Juan",
  "lastName": "Pérez",
  "email": "customer@example.com",
  "phone": "+573001234567",
  "countrySymbol": "CO",
  "documentType": "CED_CIU",
  "documentNumber": "1234567890",
  "businessType": "PERSON",
  "createdAt": "2025-11-13T10:00:00Z",
  "merchantId": "mrc_xyz789"
}

Document Types by Country

Colombia (CO)

Send the code from this table in documentType, not the abbreviation the document goes by in Colombia (CC, CE). If you send CC or CE, the API responds with a 400 error.

Document TypeCommon abbreviationCode (documentType)DescriptionExample
Cédula de CiudadaníaCCCED_CIUNational ID1234567890
Cédula de ExtranjeríaCECED_EXTForeign ID1234567
Número de Identificación TributariaNITNITTax ID (companies)9001234561 or 900.123.456-1

NIT format: accepted as 10 consecutive digits (9001234561) or with dots and a dash (900.123.456-1). Both include the check digit.

The Colombia catalog also includes RC (Registro civil), NOP (foreign NIT), PP (Passport) and DIE (foreign ID document), but they are currently not accepted when creating Colombian contacts: the API responds Document type not supported for the specified country. You can query the full catalog with GET /api/v1/documents?countrySymbol=CO.

Brazil (BR)

Document TypeCodeDescriptionExample
CPFCPFIndividual Tax ID123.456.789-09
CNPJCNPJCompany Tax ID (numeric or alphanumeric)12.345.678/0001-95 · 12.ABC.345/01DE-35

Required document

Contacts with countrySymbol: "BR" must include a CPF (individual) or a CNPJ (company). Brazilian providers reject the payment if the contact has no document, so the API validates it when the contact is created.

  • On create: always required. You can send it in documentType / documentNumber or as an entry in documents[].
  • On update: only validated if the update changes the country or the document. Existing Brazil contacts that have no document can still be edited in other fields.
  • The rule uses the contact’s country (countrySymbol), not their nationality.

If the document is missing, the API responds 400 with code CT00048. See the Error Code Catalog.

Document formats

  • CPF: 11 digits, with or without formatting (123.456.789-09).
  • CNPJ: 14 characters, with or without formatting (AA.AAA.AAA/AAAA-DV). The first 12 can be letters or digits and the last 2 (check digits) are always numeric. Since July 2026, the Receita Federal assigns alphanumeric CNPJs to new companies, and numeric CNPJs remain valid. Lowercase letters are accepted and stored as uppercase.
    • Valid examples: 12.345.678/0001-95, 12.ABC.345/01DE-35
  • The number is stored without formatting. So the same document written with formatting, without it, or in lowercase counts as a duplicate (CT00023).

Mexico (MX)

Document TypeCodeDescriptionExample
RFCRFCTax IDXAXX010101000
CURPCURPPopulation RegistryABCD123456HDFXXX09

Chile (CL)

Document TypeCodeDescriptionExample
RUTRUTTax ID11.111.111-1

Argentina (AR)

Document TypeCodeDescriptionExample
DNIDNINational ID12345678
CUITCUITTax ID20-12345678-9

Peru (PE)

Document TypeCodeDescriptionExample
Documento Nacional de IdentidadDNINational ID12345678
Registro Único de ContribuyentesRUCTax ID (companies)20123456789
Carné de ExtranjeríaCED_EXTForeign Resident ID001234567

Bolivia (BO)

Document TypeCodeDescriptionExample
Cédula de IdentidadCED_CIUNational ID1234567
Número de Identificación TributariaNITTax ID (companies)1234567890

Venezuela (VE)

Document TypeCodeDescriptionExample
Cédula de IdentidadCED_CIUNational ID (V/E prefix)V12345678
Número de Identificación TributariaNITTax ID (companies, J/G prefix)J123456789

United States (US)

Document TypeCodeDescriptionExample
Employer Identification NumberEINEmployer Tax ID12-3456789

Bank Accounts

Linking Bank Accounts to Contacts

For PAYOUT operations, you need to link a bank account to the contact:

Automatic Association: Bank accounts are automatically linked to the contact’s information. The holder name is taken from the contact’s firstName and lastName (when provided). Bank codes can be deduced from account numbers for most countries.

Optional Fields with Defaults

FieldTypeDefaultDescription
typestringVIRTUALAccount type: SAVINGS, CHECKING, or VIRTUAL. Required for Colombia, except with rail: "BREB". Optional for most countries.
isVirtualbooleanfalseWhether this is a virtual account.
isTrackedbooleanfalseWhether this account is tracked for balance monitoring.
railstring(none)Payment rail the destination is reachable through: BANK or BREB. Only meaningful in Colombia — required to store a Bre-B key. See Payment Rails.

Country-Specific Required Fields

Countryentity (bankCode)Notes
Colombia (CO)RequiredMust provide bank code — except on a Bre-B destination (rail: "BREB"), which has no bank
Chile (CL)RequiredMust provide bank code
Peru (PE)OptionalAuto-deduced from account number (CCI)
Argentina (AR)OptionalAuto-deduced from CVU/CBU
Mexico (MX)OptionalAuto-deduced from CLABE
Brazil (BR)OptionalAuto-deduced

Peru — credit times (PEN and USD): transfers to Banco BCP are instant, 24/7 except 00:00–04:00. Interbank takes about 20 minutes, Monday to Saturday 06:05–21:00. Other banks are credited on a schedule that depends on when the payout is sent, at the latest by the next business day. See Paying Providers for the full schedule and limits.

async function addBankAccountToContact(token, orgId, merchantId, contactId, bankData) {
  const response = await axios.post(
    `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/contacts/${contactId}/accounts`,
    {
      name: bankData.name,
      kind: 'BANK',
      isDefault: bankData.isDefault,
      countrySymbol: bankData.country,
      currencySymbol: bankData.currency,
      entity: bankData.entity,           // Required for CO, CL. Optional for others (auto-deduced)
      accountNumber: bankData.accountNumber,
      type: bankData.type,               // Required for Colombia: 'SAVINGS' or 'CHECKING'
      rail: bankData.rail                // Optional: 'BANK' or 'BREB'. Required for a Colombian Bre-B key
    },
    {
      headers: { 
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    }
  );
  
  return response.data;
}
 
// Usage - Colombia (entity required)
const bankAccountCO = await addBankAccountToContact(token, orgId, merchantId, 'cnt_abc123', {
  name: 'Bancolombia COP',
  isDefault: true,
  country: 'CO',
  currency: 'COP',
  entity: 'BANCOLOMBIA',     // Required for Colombia and Chile
  accountNumber: '1234567890',
  type: 'SAVINGS'            // Required for Colombia
});
 
// Usage - Peru (entity auto-deduced from CCI)
const bankAccountPE = await addBankAccountToContact(token, orgId, merchantId, 'cnt_def456', {
  name: 'Peru PEN',
  isDefault: false,
  country: 'PE',
  currency: 'PEN',
  accountNumber: '00219100012345678901'  // 20-digit CCI - bank code auto-deduced
});
 
console.log('Bank account added:', bankAccountCO.id);

Colombia — Bre-B keys: rail is optional, but send rail: "BREB" whenever accountNumber carries a Bre-B key (an email, an @alias, a phone or a document number). Without it the value is validated and settled as a bank account number: usually rejected with BAA00020 / BAA00021, and stored as a bank account when its length happens to match a real one — which pays out over the wrong rail. Declaring it also exempts you from entity and type, which a key does not have. See Payment Rails.

Terminal
# Colombia — Bre-B key as the destination
curl -X POST 'https://api-sandbox.koywe.com/api/v1/organizations/YOUR_ORG_ID/merchants/YOUR_MERCHANT_ID/contacts/cnt_abc123/accounts' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Bre-B Juan Pérez",
    "kind": "BANK",
    "isDefault": true,
    "countrySymbol": "CO",
    "currencySymbol": "COP",
    "accountNumber": "@juanperez",
    "rail": "BREB"
  }'

Country-Specific Requirements: See Merchant External Accounts for detailed validation rules by country. Contact bank accounts follow the same validations (CLABE for Mexico, CCI for Peru, CVU/CBU for Argentina, etc.).


Retrieving Contacts

List All Contacts

JavaScript
async function listContacts(token, orgId, merchantId, options = {}) {
  const response = await axios.get(
    `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/contacts`,
    {
      params: {
        search: options.search,        // Optional: search by name or email
        limit: options.limit || 50,
        page: options.page || 1
      },
      headers: { 'Authorization': `Bearer ${token}` }
    }
  );
  
  return response.data;
}
 
// Usage
const contacts = await listContacts(token, orgId, merchantId, {
  search: 'juan',
  limit: 20
});
 
console.log(`Found ${contacts.length} contacts`);

Get Specific Contact

JavaScript
async function getContact(token, orgId, merchantId, contactId) {
  const response = await axios.get(
    `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/contacts/${contactId}`,
    {
      headers: { 'Authorization': `Bearer ${token}` }
    }
  );
  
  return response.data;
}
 
// Usage
const contact = await getContact(token, orgId, merchantId, 'cnt_abc123');
console.log('Contact:', contact);

Get Contact’s Bank Accounts

JavaScript
async function getContactBankAccounts(token, orgId, merchantId, contactId) {
  const response = await axios.get(
    `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/contacts/${contactId}/accounts`,
    {
      headers: { 'Authorization': `Bearer ${token}` }
    }
  );
  
  return response.data;
}
 
// Usage
const bankAccounts = await getContactBankAccounts(token, orgId, merchantId, 'cnt_abc123');
console.log('Bank accounts:', bankAccounts);

Updating Contacts

JavaScript
async function updateContact(token, orgId, merchantId, contactId, updates) {
  const response = await axios.put(
    `https://api-sandbox.koywe.com/api/v1/organizations/${orgId}/merchants/${merchantId}/contacts/${contactId}`,
    updates,
    {
      headers: { 
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    }
  );
  
  return response.data;
}
 
// Usage - Update phone number or address
const updated = await updateContact(token, orgId, merchantId, 'cnt_abc123', {
  phone: '+573009876543',
  addressLine1: 'Calle 456',
  city: 'Medellín'
});

Validation Requirements

Person vs Company

For PERSON (individual):

  • Use individual document types (CED_CIU, DNI, CPF, etc.)
  • businessType: "PERSON"
  • Individual’s firstName (and optionally lastName)

For COMPANY (business):

  • Use company document types (NIT, CNPJ, CUIT, etc.)
  • businessType: "COMPANY"
  • type: "BUSINESS"
  • Company legal name as firstName

Document Number Formats

Document numbers must match the expected format for each country:

  • Colombia CED_CIU / CED_EXT: digits only (up to 15)
  • Colombia NIT: 10 digits (9001234561) or with dots and dash (900.123.456-1)
  • Brazil CPF: 11 digits (with or without formatting)
  • Brazil CNPJ: 14 characters, numeric or alphanumeric (with or without formatting)
  • Mexico RFC: 12-13 characters
  • Chile RUT: Format XX.XXX.XXX-X

Best Practices

When to Create Contacts

Create contacts for:

  • Customers making payments (PAYIN) - for tracking and compliance
  • Providers receiving payments (PAYOUT) - required for bank account linking
  • Recurring transactions with the same entity

Reusing Contacts

Reuse existing contacts for the same customer/provider to:

  • Maintain payment history
  • Avoid duplicate records
  • Simplify reconciliation
JavaScript
// Check if contact exists before creating
async function getOrCreateContact(token, orgId, merchantId, email) {
  // Try to find existing
  const contacts = await listContacts(token, orgId, merchantId, { search: email });
  
  if (contacts.length > 0) {
    return contacts[0];  // Return existing
  }
  
  // Create new if not found
  return await createContact(token, orgId, merchantId, {
    email: email,
    // ... other fields
  });
}

Data Privacy

Security Considerations:

  • Store only necessary information
  • Follow GDPR/data protection regulations
  • Don’t store sensitive data in metadata fields
  • Implement proper access controls

Common Scenarios

Scenario 1: E-Commerce Customer Payment

JavaScript
// 1. Create customer contact
const customer = await createContact(token, orgId, merchantId, {
  firstName: 'María',
  lastName: 'García',
  countrySymbol: 'CO',
  businessType: 'PERSON',
  type: 'PERSON',
  email: 'customer@example.com',
  documentType: 'CED_CIU',
  documentNumber: '1234567890',
  phone: '+573001234567'
});
 
// 2. Create PAYIN order linked to contact
const order = await createPayinOrder(token, orgId, merchantId, {
  contactId: customer.id,
  amount: 50000,
  currency: 'COP',
  // ... other fields
});

Scenario 2: Provider Payout

JavaScript
// 1. Create provider contact
const provider = await createContact(token, orgId, merchantId, {
  firstName: 'Servicios ABC SAS',
  countrySymbol: 'CO',
  businessType: 'COMPANY',
  type: 'BUSINESS',
  email: 'provider@example.com',
  documentType: 'NIT',
  documentNumber: '9001234561'
});
 
// 2. Add provider's bank account
const bankAccount = await addBankAccountToContact(token, orgId, merchantId, provider.id, {
  name: 'Bancolombia COP',
  kind: 'BANK',
  isDefault: true,
  countrySymbol: 'CO',
  currencySymbol: 'COP',
  entity: 'BANCOLOMBIA',
  accountNumber: '1234567890',
  type: 'CHECKING'
});
 
// 3. Create PAYOUT order
const payout = await createPayoutOrder(token, orgId, merchantId, {
  contactId: provider.id,
  destinationAccountId: bankAccount.id,  // Link to bank account
  amount: 500000,
  currency: 'COP'
});

Next Steps