Import customers from CSV with structured preview
Imports multiple customers from a CSV file with full preview of all records. **Key features**: - **Structured preview**: Returns all parsed records (valid and with errors) - **Parallel validation**: NIFs validated concurrently against VeriFactu - **Granular feedback**: Customer-specific errors and warnings - **Editable data**: Structured JSON for editable table in frontend **Recommended flow**: 1. **Initial upload**: Call with `dry_run=true` to get preview 2. **Display table**: Frontend shows parsed data with errors/warnings 3. **Inline editing**: User corrects data directly in the table 4. **Final import**: Send corrected data with `dry_run=false` **Format**: Must follow CSV template format (downloadable from `/customers/template-csv`). **Security limits**: - Max size: 5MB - Max 1,000 records per file - Rate limiting: 3 imports per hour **Validation**: - Required headers per template - Full validation of each row with business rules - Parallel NIF validation against AEAT registry (VeriFactu) - Duplicate detection in CSV and database **Validation statuses**: - `VALID`: Customer valid, ready to import - `WARNING`: Customer valid but with warnings (eg: missing email) - `ERROR`: Customer invalid, cannot process - `DUPLICATE`: Duplicate customer (in CSV or DB) - `NIF_INVALID`: NIF invalid in AEAT registry
API Key authentication.
Format: Authorization: Bearer beel_sk_<key>
Scopes: API Keys use the same scopes as OAuth2 tokens. Each key is created with
specific scopes that limit which endpoints it can access. The required scope for each
endpoint is documented in the operation's security section under OAuth2.
Obtaining Keys: API Keys are managed from the BeeL dashboard
Security: API Keys are secret credentials. Do not share them or store them in source code
In: header
CSV file with customers to import
If true (recommended initially): preview only without persistence. If false: preview + persistence of valid customers.
trueResponse Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://app.beel.es/api/v1/customers/import-csv-preview" \ -F file="string"{
"success": true,
"data": {
"metadata": {
"total_customers": 10,
"is_dry_run": true,
"processing_time_ms": 450,
"source_type": "CSV_IMPORT",
"filename": "clientes_enero.csv",
"file_size_bytes": 1048576,
"total_rows": 250
},
"customers_validation": [
{
"index": 0,
"customer": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"legal_name": "Empresa Cliente SL",
"trade_name": "EmpresaCliente",
"nif": "12345678A",
"address": {
"street": "Calle Mayor, 123",
"number": "123",
"floor": "2º A",
"door": "A",
"postal_code": "28001",
"city": "Madrid",
"province": "Madrid",
"country": "España",
"country_code": "ES"
},
"phone": "+34 612 345 678",
"email": "user@example.com",
"web": "string",
"billing_emails": [
"user@example.com"
],
"contact_person": "María García",
"notes": "string",
"preferred_payment_method": {
"method": "BANK_TRANSFER",
"iban": "ES1234567890123456789012",
"swift": "ABCDESMMXXX",
"payment_term_days": 30
},
"general_discount": 0,
"active": true,
"created_at": "2019-08-24T14:15:22Z",
"updated_at": "2019-08-24T14:15:22Z",
"alternative_id": {
"type": "NIF_IVA",
"number": "string",
"country_code": "st"
}
},
"status": "VALID",
"errors": [
{
"field": "nif",
"value": "12345678X",
"message": "NIF not found in AEAT census"
}
],
"warnings": [
{
"field": "email",
"message": "Email not provided, NIF will be used for invoicing"
}
],
"row_number": 15
}
],
"statistics": {
"total_processed": 10,
"valid": 6,
"with_warnings": 2,
"with_errors": 2,
"duplicates": 1,
"invalid_nifs": 1,
"imported": 0,
"success_rate": 0.8,
"importable": 8,
"not_importable": 2
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message",
"file_size_mb": 0,
"record_count": 0,
"missing_headers": [
"string"
]
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The provided data is not valid",
"details": {
"field": "specific error message"
}
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "INTERNAL_ERROR",
"message": "Internal server error"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}Get customer by ID GET
Retrieves complete details of a specific customer
Import contacts from Holded Excel POST
Imports multiple customers from an Excel file exported from Holded. **Key features**: - **Specific parsing**: Reads exact structure of Holded contacts Excel (29 columns) - **Automatic mapping**: Converts Holded contacts to Customer entities automatically - **Full validation**: Validates NIFs, addresses and required data - **Preview mode**: Allows viewing parsed data before importing **Recommended flow**: 1. **Initial upload**: Call with `preview=true` to get preview 2. **Display data**: Frontend shows parsed Holded contacts 3. **Final import**: Call with `preview=false` to import definitively **Expected Excel structure** (contacts exported from Holded): - Sheet: "Holded" - Rows to skip: 2 (header + empty) - Headers in row 2: Created, Name, ID, Email, Phone, Mobile, etc. (29 columns) - Footer: "Report created automatically with Holded..." **Security limits**: - Max size: 10MB - Max 5,000 records per file - Rate limiting: 5 imports per hour **Automatic Holded → Customer mapping**: - Name → legal_name - ID → identifier (NIF/CIF) - Email → email - Phone/Mobile → phone (prioritizes mobile) - Full address → address - Tags → notes