Delete several customers
Scopecustomers:writeDeletes the customers listed in ids.
- Deprecated: use
DELETE /v1/companies/{company_id}/customers/bulk, which behaves identically.
Partial results
- Partial: the customers that can be deleted are deleted, and the rest keep their
place in
customers_deletionwith the status that explains why. HAS_INVOICES: a customer that has invoices cannot be deleted and comes back with that row status.
What deleting means
- Semantics: each deletion behaves as
DELETE /v1/customers/{customer_id}. The customer is retained for tax record-keeping purposes but is no longer exposed by the API, its identifier is released for reuse, and invoices already issued to it keep their own copy of the recipient's details. - Not deactivating: deleting frees the identifier, so the same NIF can be registered
again, while
PATCHwithactive: falseleaves the customer where it is with its NIF still taken.
Keys are prefixed beel_sk_, and each one carries the scopes it was created with: a key
short of the scope an operation needs is answered 403. The scope an operation requires
is shown next to its title, and the full catalogue lives in the Scopes reference.
Keys are created from the BeeL dashboard. They are secret credentials: do not share them or commit them to source control.
In: header
Query Parameters
Comma-separated customer IDs
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X DELETE "https://app.beel.es/api/v1/customers/bulk?ids=550e8400-e29b-41d4-a716-446655440000%2C550e8400-e29b-41d4-a716-446655440001"{
"success": true,
"data": {
"metadata": {
"total_customers": 10,
"operation": "DELETE_CUSTOMERS",
"is_dry_run": false
},
"customers_deletion": [
{
"index": 0,
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "DELETED",
"error": {
"code": "CLIENT_HAS_INVOICES",
"message": "A customer with invoices cannot be deleted: its tax record is kept intact. Deactivate it (active: false) to stop using it."
}
}
],
"statistics": {
"total_processed": 10,
"deleted": 7,
"not_found": 1,
"has_invoices": 2,
"errors": 0
},
"deleted_ids": [
"550e8400-e29b-41d4-a716-446655440000"
],
"deactivated_ids": [
"550e8400-e29b-41d4-a716-446655440000"
],
"total": 10,
"successful": 8,
"failed": 2,
"errors": [
{
"customer_id": "550e8400-e29b-41d4-a716-446655440000",
"error": {
"code": "CLIENT_HAS_INVOICES",
"message": "A customer with invoices cannot be deleted: its tax record is kept intact. Deactivate it (active: false) to stop using it."
}
}
]
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "BAD_REQUEST",
"message": "Invalid request"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication is required to access this resource"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "FORBIDDEN",
"message": "You do not have permission to access this resource"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please try again in 60 seconds."
},
"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"
}
}{
"success": false,
"error": {
"code": "UNSUPPORTED_MEDIA_TYPE",
"message": "Unsupported media type: text/plain. Supported: application/json"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
}
}Import customers from a Holded contacts export POST
Parses a contacts export from Holded (`.xlsx`) as Holded produces it, maps each contact to a customer and returns every row with its validation outcome, as the CSV import does. - **Deprecated:** use `POST /v1/companies/{company_id}/customers/imports` with `source: holded`, which imports the same file. It answers `201` and requires the `Idempotency-Key` header. - **Mapping:** the contact name becomes `legal_name`, the Holded ID becomes the tax identifier, and mobile takes precedence over landline for the phone. - **File:** limited to 10 MB and 5,000 contacts. - **`preview`:** at its default `true` nothing is persisted; `false` also imports the mapped customers.
List the products of a company GET
Returns a paginated list of the products/services of this company (NIF), with optional filters. - **`q`:** searching is done on this collection, there is no separate search path. `q` matches the name, the code and the description, so it returns at least everything the withdrawn `GET /v1/products/search` returned, in the paginated envelope of this list.