NewThree filters returned the wrong rows
BeeL
Get StartedMulti-NIFVeriFactuStripeAPI ReferenceChangelog
Customers

Create a customer for a company

Scopecustomers:write

Creates a new customer under this company (NIF).

  • Idempotency-Key: it identifies the same operation on the deprecated flat route, so a retry that switches route replays instead of creating twice.

POST
/v1/companies/{company_id}/customers
AuthorizationBearer <token>

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

Path Parameters

company_idstring

NIF (company) the operation acts on. It is the only source of context: the account that owns it is derived from it, and the BeeL-Active-Company header plays no part. A NIF you do not reach answers 403, and so does a NIF that does not exist, so the existence of a NIF in another account is never disclosed.

Formatuuid

Header Parameters

Idempotency-Key?string

Idempotency key to prevent duplicates in sensitive operations.

  • Any unique client-generated string (e.g. an order id). A UUID also works but is not required
  • Allowed characters: letters, digits, _ and - (max 255 chars)
  • If the same key is sent twice, the result of the first operation is returned
  • Keys expire 24 hours after processing

The key is scoped per user and environment, and bound to the request body, so retrying after a network timeout replays the stored response instead of repeating the operation.

StatusCodeWhen
400INVALID_IDEMPOTENCY_KEYThe key breaks the format rules above.
409IDEMPOTENCY_KEY_PROCESSINGThe first request is still in flight. Wait and retry with the same key.
409IDEMPOTENCY_KEY_MISMATCHThe key was already used with a different body. Use a new key.
Match^[a-zA-Z0-9_-]+$
Lengthlength <= 255
legal_namestring

Customer legal name (required).

When you also send a Spanish nif, how it is used depends on the customer: for an individual the AEAT census matches NIF and name together, so a name it does not recognise makes the customer invalid; for a company the name is not verified and only the CIF decides.

Match^\S.*$
Length1 <= length <= 120
trade_name?string|null

Customer trade name. Optional, but not empty by default: leave it out on creation and it is filled with legal_name, which is what then shows as the recipient's trade name on the invoice PDF. Send it explicitly if the two differ.

The default applies on creation only. A PUT replaces the customer whole, so omitting trade_name there clears it instead of refilling it from legal_name.

Lengthlength <= 120
nif?string
alternative_id?|null

Alternative identifier for customers without Spanish Tax ID.

VeriFactu rules (enforced server-side, returns 422 ALTERNATIVE_ID_INVALID on violation)

  • If country_code = ES, then type must be PASSPORT (03) or NOT_REGISTERED (07).
  • If type = NOT_REGISTERED (07), then country_code must be ES.

Matrix of allowed combinations

typecountry_code = EScountry_code ≠ ES
NIF_IVA (02)
PASSPORT (03)
COUNTRY_ID (04)
RESIDENCE_CERTIFICATE (05)
OTHER_DOCUMENT (06)
NOT_REGISTERED (07)
address

Address you send when you create or update a company, a customer or an onboarding. The street number is mandatory here: an address without it is rejected with 422.

Addresses you read back are described by their own schema, and do not guarantee the street number: records registered before it was collected have none.

phone?string

Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +

Match^[+]?[0-9\s\-\(\)]+$
Length9 <= length <= 20
email?string|null

Email address (minimum valid email is 5 chars, e.g. a@b.co)

Formatemail
Length5 <= length <= 255
website?string|null

Website URL

Match^(https?://.+|)$
Lengthlength <= 255
billing_emails?|null

Additional emails for invoice delivery (optional)

contact_person?string|null

Contact person name (optional)

Lengthlength <= 200
notes?string|null

Additional notes about the customer (optional)

preferred_payment_method?
general_discount?number|null

General discount percentage (optional)

Range0 <= value <= 100

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://app.beel.es/api/v1/companies/497f6eca-6276-4993-bfeb-53cbbbba6f08/customers" \  -H "Content-Type: application/json" \  -d '{    "legal_name": "Tech Solutions SL",    "nif": "B12345674",    "email": "admin@techsolutions.com",    "phone": "+34912345678",    "address": {      "street": "Calle Mayor",      "number": "123",      "floor": "2º B",      "postal_code": "28013",      "city": "Madrid",      "province": "Madrid",      "country": "España"    },    "notes": "Cliente prioritario - Pago puntual"  }'

Customer created successfully with generated ID and initial statistics

{
  "success": true,
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "legal_name": "Tech Solutions SL",
    "nif": "B12345674",
    "email": "admin@techsolutions.com",
    "phone": "+34912345678",
    "address": {
      "street": "Calle Mayor",
      "number": "123",
      "floor": "2º B",
      "postal_code": "28013",
      "city": "Madrid",
      "province": "Madrid",
      "country": "España"
    },
    "notes": "Cliente prioritario - Pago puntual",
    "active": true,
    "created_at": "2025-01-20T10:00:00Z",
    "updated_at": "2025-01-20T10:00:00Z"
  },
  "meta": {
    "timestamp": "2025-01-20T10:00:00Z",
    "request_id": "c1c1c1c1-0001-4000-a000-000000000001"
  }
}
{
  "success": false,
  "error": {
    "code": "INVALID_JSON_FORMAT",
    "message": "The field 'due_date' has an invalid date format: '2026-03-04fds'. Expected format: YYYY-MM-DD.",
    "details": {
      "field": "due_date",
      "invalid_value": "2026-03-04fds",
      "expected_format": "YYYY-MM-DD"
    }
  },
  "meta": {
    "timestamp": "2026-03-05T10: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": "VALIDATION_ERROR",
    "message": "The provided data is not valid",
    "details": {
      "field": "specific error message"
    }
  },
  "meta": {
    "timestamp": "2025-01-15T10:30:00Z",
    "request_id": "4bf92f3577b34da6a3ce929d0e0e4736"
  },
  "type": "https://docs.beel.es/errors/INVOICE_NO_LINES",
  "title": "INVOICE_NO_LINES",
  "detail": "La factura debe tener al menos una línea",
  "instance": "/v1/invoices/abc-123"
}

Duplicate resource exists (NIF, email, invoice number, series code)

{
  "success": false,
  "error": {
    "code": "CONFLICT",
    "message": "Resource already exists",
    "details": {
      "conflict_type": "DUPLICATE_NIF",
      "field": "nif",
      "value": "B12345674",
      "existing_resource_id": "123e4567-e89b-12d3-a456-426614174000",
      "message": "A customer with NIF B12345674 already exists"
    }
  },
  "meta": {
    "timestamp": "2025-01-20T10:00:00Z",
    "request_id": "d4d4d4d4-0004-4000-a000-000000000004"
  }
}

Request data fails validation (missing fields, invalid format, business rules)

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": {
      "errors": [
        {
          "field": "nif",
          "message": "Invalid NIF format. Expected 9 characters (8 digits + letter or letter + 8 digits)",
          "value": "B123INVALID"
        },
        {
          "field": "lines",
          "message": "At least one line item is required",
          "value": []
        },
        {
          "field": "recipient.address.postal_code",
          "message": "Invalid postal code format. Expected 5 digits",
          "value": "280"
        },
        {
          "field": "lines[0].unit_price",
          "message": "Unit price must be greater than or equal to 0",
          "value": -10.5
        }
      ]
    }
  },
  "meta": {
    "timestamp": "2025-01-20T10:00:00Z",
    "request_id": "c3c3c3c3-0003-4000-a000-000000000003"
  }
}
{
  "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"
  }
}