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?
Track payment history per customer or provider
Store KYC/compliance information (documents, tax IDs)
Link bank accounts for easy recurring payments
Generate reports per contact or business type
Contact Structure
Required Fields
{
"email": "customer@example.com", // Mandatory
"fullName": "Juan Pérez", // Full legal name
"countrySymbol": "CO", // Country code
"businessType": "PERSON" // PERSON, COMPANY, etc.
}Optional Fields
{
"phone": "+573001234567", // Phone number
"documentType": "CC", // ID document type
"documentNumber": "1234567890", // ID document number
"taxIdType": "NIT", // Tax ID type
"taxIdNumber": "900123456", // Tax ID number
"address": {
"street": "Calle 123",
"city": "Bogotá",
"state": "Cundinamarca",
"zipCode": "110111",
"country": "CO"
}
}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`,
{
email: contactData.email,
phone: contactData.phone,
fullName: contactData.fullName,
countrySymbol: contactData.country,
documentType: contactData.documentType,
documentNumber: contactData.documentNumber,
businessType: 'PERSON' // or 'COMPANY'
},
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
}
// Usage - Creating a customer contact
const customer = await createContact(token, orgId, merchantId, {
email: 'customer@example.com',
phone: '+573001234567',
fullName: 'Juan Pérez',
country: 'CO',
documentType: 'CC',
documentNumber: '1234567890'
});
console.log('Contact created:', customer.id);def create_contact(token, org_id, merchant_id, contact_data):
response = requests.post(
f'https://api-sandbox.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/contacts',
json={
'email': contact_data['email'],
'phone': contact_data['phone'],
'fullName': contact_data['full_name'],
'countrySymbol': contact_data['country'],
'documentType': contact_data['document_type'],
'documentNumber': contact_data['document_number'],
'businessType': 'PERSON'
},
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
)
return response.json()
# Usage
customer = create_contact(token, org_id, merchant_id, {
'email': 'customer@example.com',
'phone': '+573001234567',
'full_name': 'Juan Pérez',
'country': 'CO',
'document_type': 'CC',
'document_number': '1234567890'
})curl -X POST 'https://api-sandbox.koywe.com/api/v1/organizations/YOUR_ORG_ID/merchants/YOUR_MERCHANT_ID/contacts' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{
"email": "customer@example.com",
"phone": "+573001234567",
"fullName": "Juan Pérez",
"countrySymbol": "CO",
"documentType": "CC",
"documentNumber": "1234567890",
"businessType": "PERSON"
}'Response:
{
"id": "cnt_abc123",
"email": "customer@example.com",
"phone": "+573001234567",
"fullName": "Juan Pérez",
"countrySymbol": "CO",
"documentType": "CC",
"documentNumber": "1234567890",
"businessType": "PERSON",
"createdAt": "2025-11-13T10:00:00Z",
"merchantId": "mrc_xyz789"
}Document Types by Country
Colombia (CO)
| Document Type | Code | Description | Example |
|---|---|---|---|
| Cédula de Ciudadanía | CC | National ID | 1234567890 |
| Cédula de Extranjería | CE | Foreign ID | 1234567 |
| NIT | NIT | Tax ID (companies) | 900123456-1 |
Brazil (BR)
| Document Type | Code | Description | Example |
|---|---|---|---|
| CPF | CPF | Individual Tax ID | 123.456.789-00 |
| CNPJ | CNPJ | Company Tax ID | 12.345.678/0001-90 |
Mexico (MX)
| Document Type | Code | Description | Example |
|---|---|---|---|
| RFC | RFC | Tax ID | XAXX010101000 |
| CURP | CURP | Population Registry | ABCD123456HDFXXX09 |
Chile (CL)
| Document Type | Code | Description | Example |
|---|---|---|---|
| RUT | RUT | Tax ID | 11.111.111-1 |
Argentina (AR)
| Document Type | Code | Description | Example |
|---|---|---|---|
| DNI | DNI | National ID | 12345678 |
| CUIT | CUIT | Tax ID | 20-12345678-9 |
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 fullName. Bank codes can be deduced from account numbers for most countries.
Optional Fields with Defaults
| Field | Type | Default | Description |
|---|---|---|---|
accountType | string | VIRTUAL | Account type: SAVINGS, CHECKING, or VIRTUAL. Required for Colombia. Optional for most countries. |
isVirtual | boolean | false | Whether this is a virtual account. |
isTracked | boolean | false | Whether this account is tracked for balance monitoring. |
Country-Specific Required Fields
| Country | entity (bankCode) | Notes |
|---|---|---|
| Colombia (CO) | Required | Must provide bank code |
| Chile (CL) | Required | Must provide bank code |
| Peru (PE) | Optional | Auto-deduced from account number (CCI) |
| Argentina (AR) | Optional | Auto-deduced from CVU/CBU |
| Mexico (MX) | Optional | Auto-deduced from CLABE |
| Brazil (BR) | Optional | Auto-deduced |
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`,
{
countrySymbol: bankData.country,
currencySymbol: bankData.currency,
entity: bankData.entity, // Required for CO, CL. Optional for others (auto-deduced)
accountNumber: bankData.accountNumber,
accountType: bankData.accountType // Required for Colombia: 'SAVINGS' or 'CHECKING'
},
{
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
}
// Usage - Colombia (entity required)
const bankAccountCO = await addBankAccountToContact(token, orgId, merchantId, 'cnt_abc123', {
country: 'CO',
currency: 'COP',
entity: 'BANCOLOMBIA', // Required for Colombia and Chile
accountNumber: '1234567890',
accountType: 'SAVINGS' // Required for Colombia
});
// Usage - Peru (entity auto-deduced from CCI)
const bankAccountPE = await addBankAccountToContact(token, orgId, merchantId, 'cnt_def456', {
country: 'PE',
currency: 'PEN',
accountNumber: '00219100012345678901' // 20-digit CCI - bank code auto-deduced
});
console.log('Bank account added:', bankAccountCO.id);def add_bank_account_to_contact(token, org_id, merchant_id, contact_id, bank_data):
payload = {
'countrySymbol': bank_data['country'],
'currencySymbol': bank_data['currency'],
'accountNumber': bank_data['account_number']
}
# entity required for CO, CL; optional for others
if bank_data.get('entity'):
payload['entity'] = bank_data['entity']
# accountType required for Colombia; optional for other countries (defaults to VIRTUAL)
if bank_data.get('account_type'):
payload['accountType'] = bank_data['account_type']
response = requests.post(
f'https://api-sandbox.koywe.com/api/v1/organizations/{org_id}/merchants/{merchant_id}/contacts/{contact_id}/accounts',
json=payload,
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
)
return response.json()
# Usage - Colombia (entity required)
bank_account_co = add_bank_account_to_contact(token, org_id, merchant_id, 'cnt_abc123', {
'country': 'CO',
'currency': 'COP',
'entity': 'BANCOLOMBIA', # Required for Colombia and Chile
'account_number': '1234567890',
'account_type': 'SAVINGS' # Required for Colombia
})
# Usage - Chile (entity required)
bank_account_cl = add_bank_account_to_contact(token, org_id, merchant_id, 'cnt_ghi789', {
'country': 'CL',
'currency': 'CLP',
'entity': 'BANCO_ESTADO', # Required for Chile
'account_number': '12345678901'
})# Colombia - entity required
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 '{
"countrySymbol": "CO",
"currencySymbol": "COP",
"entity": "BANCOLOMBIA",
"accountNumber": "1234567890",
"accountType": "SAVINGS"
}'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
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
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
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
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',
address: {
street: 'Calle 456',
city: 'Medellín'
}
});Validation Requirements
Person vs Company
For PERSON (individual):
- Use individual document types (CC, DNI, CPF, etc.)
businessType:"PERSON"- Individual’s full name
For COMPANY (business):
- Use company document types (NIT, CNPJ, CUIT, etc.)
businessType:"COMPANY"- Company legal name
Document Number Formats
Document numbers must match the expected format for each country:
- Colombia CC: 6-10 digits
- Brazil CPF: 11 digits (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
// 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
// 1. Create customer contact
const customer = await createContact(token, orgId, merchantId, {
email: 'customer@example.com',
fullName: 'María García',
country: 'CO',
documentType: 'CC',
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
// 1. Create provider contact
const provider = await createContact(token, orgId, merchantId, {
email: 'provider@example.com',
fullName: 'Servicios ABC SAS',
country: 'CO',
documentType: 'NIT',
documentNumber: '900123456-1',
businessType: 'COMPANY'
});
// 2. Add provider's bank account
const bankAccount = await addBankAccountToContact(token, orgId, merchantId, provider.id, {
country: 'CO',
currency: 'COP',
entity: 'BANCOLOMBIA', // Required for Colombia
accountNumber: '1234567890',
accountType: 'CHECKING' // Required for Colombia
// holderName auto-linked from provider.fullName
});
// 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'
});