Validate a NIF against the AEAT register
Scopenif:validateChecks a NIF or CIF against the AEAT register through VeriFactu and returns what the register says about it. It only reads the register: it creates nothing and stores no customer.
status: distinguishes a NIF found in the register from one that is syntactically correct but absent, and from a check that could not be completed because VeriFactu was unavailable — in which case the NIF is validated automatically once the service is back.valid: true: means different things by holder. For an individual, AEAT matched NIF and name together. For a legal entity the name you sent is not verified at all — AEAT identifies a company by its CIF alone — so it says nothing about your name.legal_name_verified: tells those two cases apart.census_status: says whether an identified NIF is also deregistered or revoked.
Invalid input
- Bad syntax is an answer, not an error: it comes back
200withstatus: INVALID, so a pre-validation flow never has to tell rejections apart by status code. - A missing NIF is an error: an absent or empty
nifanswers422FIELD_BLANK, withdetails.fieldnaming it.
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
Last name and first name (individual) or business name (legal entity).
Important:
- REQUIRED for individuals (NIFs starting with a number)
- OPTIONAL for legal entities (NIFs starting with a letter)
For an individual, AEAT matches NIF and name together: send a name the
census does not recognise and the person is not identified, so the status
comes back INVALID.
For a legal entity, the name is not verified. AEAT identifies a
company by its CIF alone — there is no census answer meaning "this name is
wrong", so validation depends only on the CIF and any name you send is
accepted. Use the legal_name of the response to contrast your own.
1 <= length <= 255Response Body
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/nif/validate" \ -H "Content-Type: application/json" \ -d '{ "nif": "B12345674" }'{
"success": true,
"data": {
"valid": true,
"status": "VALID",
"legal_name": "JUAN PEREZ GARCIA",
"legal_name_verified": true,
"census_status": "IDENTIFIED",
"message": "NIF successfully validated in AEAT registry",
"validated_at": "2025-01-15T10:30:00Z"
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "123e4567-e89b-12d3-a456-426614174000"
}
}{
"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": "VALIDATION_ERROR",
"message": "Validation error",
"details": {
"field_name": "Field is required"
}
},
"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"
}
}Get invoice customization options GET
**Deprecated.** Use `GET /v1/invoice-customization-options`, which returns exactly the same body. The catalogue is the same for every credential, so it does not belong under `/v1/configuration`. Returns, in `template_types`, the catalogue of PDF templates a NIF can be rendered with. - **Fields:** each entry carries the `code` to send as `template_type`, plus a `name` and a short `description` translated into the language of the user the credential belongs to. - **Removed fields:** `suggested_colors`, `features` and `preview_url` are no longer returned; the invoice customization accepts any 6-digit hexadecimal colour, so pick your own.
Get my identity GET
Returns the identity of the authenticated principal: the account the credential belongs to, the person's email, name, logo and interface language, and a description of the credential itself. Unlike every other operation, it requires no scope — any valid credential resolves, so a `200` confirms the credential works and tells you which account it belongs to, and a `401` that it does not. - **`account_id`:** identifies who the credential belongs to, not what it is currently pointed at; selecting a different company with `BeeL-Active-Company` does not change it. - **`name`:** resolves as `trade_name ?? legal_name` of the active fiscal profile, and is `null` until onboarding creates one. - **`credential`:** describes the credential the call was authenticated with — its type, the environment it operates on and the permissions it holds — so a client can adapt what it offers instead of discovering the limits through a `403`. - **Caching:** responses are never cached (`Cache-Control: no-store`).