# BeeL API Documentation
Complete API documentation for the BeeL invoicing platform.
Public invoicing API for self-employed professionals in Spain with full VeriFactu support.
---
# Authentication
How to authenticate your requests to the BeeL. API
All API requests require authentication via an API Key using the standard **Bearer token** scheme. This page explains how to get your key and use it in your requests.
## Get your API Key
1. Log in to your BeeL. account at app.beel.es
2. Go to **Settings > API Keys**
3. Click **Create API Key**
4. Select the environment (sandbox or production)
5. Give it a descriptive name (e.g., "My App" or "ERP Integration")
6. Copy the key immediately — it's only shown once
## API Key Format
| Component | Description |
|-----------|-------------|
| **Prefix** | `beel_sk_test_` (sandbox) or `beel_sk_live_` (production) |
| **Identifier** | Unique alphanumeric string |
**Sandbox key example:**
```
beel_sk_test_a1b2c3d4e5f6g7h8
```
**Production key example:**
```
beel_sk_live_x9y8z7w6v5u4t3s2
```
**Important:** Keys are only shown **once** when created. Store them securely immediately.
**Key properties:**
- Each key is tied to a specific environment (sandbox or production)
- The base URL is the same (`https://app.beel.es/api/v1`) — the key determines the environment
- Keys never expire but can be manually revoked from the dashboard
## Making Authenticated Requests
Include your API Key in the `Authorization` header using the **Bearer scheme**:
```bash
curl https://app.beel.es/api/v1/invoices \
-H "Authorization: Bearer beel_sk_xxx"
```
### Example: List invoices
```bash
curl https://app.beel.es/api/v1/invoices \
-H "Authorization: Bearer beel_sk_test_a1b2c3d4e5f6g7h8"
```
### Example: Create an invoice
```bash
curl -X POST https://app.beel.es/api/v1/invoices \
-H "Authorization: Bearer beel_sk_test_a1b2c3d4e5f6g7h8" \
-H "Content-Type: application/json" \
-d '{
"type": "STANDARD",
"issue_date": "2025-01-15",
"recipient": {
"recipient_type": "EXISTING",
"customer_id": "550e8400-e29b-41d4-a716-446655440000"
},
"lines": [
{
"description": "Consulting",
"quantity": 1,
"unit_price": 100.00
}
]
}'
```
## Using Environment Variables
Never include your API Key directly in your code. Use environment variables instead:
```bash
# Set the environment variable
export BEEL_API_KEY="beel_sk_test_a1b2c3d4e5f6g7h8"
# Use it in your requests
curl https://app.beel.es/api/v1/invoices \
-H "Authorization: Bearer $BEEL_API_KEY"
```
### Node.js
```javascript
const apiKey = process.env.BEEL_API_KEY;
const response = await fetch('https://app.beel.es/api/v1/invoices', {
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
});
```
### Python
```python
import os
import requests
api_key = os.environ.get('BEEL_API_KEY')
response = requests.get(
'https://app.beel.es/api/v1/invoices',
headers={'Authorization': f'Bearer {api_key}'}
)
```
### PHP
```php
$apiKey = getenv('BEEL_API_KEY');
$ch = curl_init('https://app.beel.es/api/v1/invoices');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json'
]);
$response = curl_exec($ch);
```
## Using Official SDKs (Coming Soon)
The easiest way to authenticate will be using our official SDKs, currently under development:
### Node.js SDK
```typescript
import { BeeL } from '@beel_es/sdk';
const client = new BeeL({
apiKey: process.env.BEEL_API_KEY,
});
// SDK handles Bearer authentication automatically
const invoices = await client.invoices.list();
```
### Java SDK
```java
import es.beel.sdk.BeeL;
BeeL client = new BeeL(System.getenv("BEEL_API_KEY"));
// SDK handles Bearer authentication automatically
var invoices = client.invoices().list();
```
See the [SDKs documentation](/sdks) for more details.
## Authentication Errors
If authentication fails, you'll receive a `401 Unauthorized` response:
```json
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
}
```
Common causes:
- Missing `Authorization` header
- Incorrect format (must be `Bearer {key}`, not just the key)
- Incorrect API Key or typo
- API Key was deleted or regenerated
- Using a sandbox key to access production data (or vice versa)
## Environments
BeeL. provides two separate environments:
| Environment | Key Prefix | Purpose |
|-------------|------------|---------|
| **Sandbox** | `beel_sk_test_` | Testing and development. Data is isolated. |
| **Production** | `beel_sk_live_` | Real invoices sent to AEAT (VeriFactu). |
**Both environments:**
- Share the same API base URL: `https://app.beel.es/api/v1`
- Have separate data (customers, invoices, etc.)
- Use the same API endpoints and features
**Sandbox environment:**
- ✅ Test freely without affecting real invoices
- ✅ Invoices don't count towards your monthly limit
- ✅ No VeriFactu submissions sent to AEAT
- ✅ Perfect for CI/CD pipelines and development
**Production environment:**
- ⚠️ Real invoices sent to AEAT via VeriFactu
- ⚠️ Invoices count towards your monthly limit
- ⚠️ Invoice numbers are legally binding
## Security Best Practices
**Treat API keys like passwords.** Anyone with your key can create invoices and access your data.
### Do's ✅
- **Use environment variables** to store keys (never hardcode)
- **Create separate keys** for different apps or environments
- **Delete unused keys** immediately from the dashboard
- **Rotate keys regularly** (e.g., every 90 days)
- **Use sandbox keys** for all development and testing
- **Store keys in secret managers** (AWS Secrets Manager, HashiCorp Vault, etc.)
### Don'ts ❌
- **Never commit keys** to Git repositories
- **Never share keys** via email, Slack, or public channels
- **Never log keys** in application logs
- **Never use production keys** in development
- **Never include keys** in client-side code (frontend apps)
### If a key is compromised:
1. **Immediately revoke** the key from the dashboard
2. **Create a new key** with a different name
3. **Update your applications** with the new key
4. **Review recent API activity** for suspicious behavior
## Next Steps
Now that you can authenticate your requests:
1. **[Explore the SDKs](/sdks)** — Use our official libraries (Node.js, Java)
2. **[Learn about idempotency](/guides/idempotency)** — Implement safe retries
3. **[Browse the API reference](/invoices/listInvoices)** — See all available endpoints
4. **[Set up webhooks](/webhooks)** — Get real-time notifications
Questions? Email us at [it@beel.es](mailto:it@beel.es).
---
# Changelog
Track all updates to the BeeL. API.
import { Changelog } from '@/components/changelog';
---
# Claude Code
Use the BeeL. API skill for Claude Code to integrate the BeeL. API in your projects with AI assistance.
The BeeL skill for Claude Code gives your AI assistant the context it needs to implement the BeeL. API correctly: authentication, idempotency, error handling, API-first patterns, and where to find the always-up-to-date spec.
## Prerequisites
- [Claude Code](https://claude.ai/claude-code) installed
- A BeeL. API key — get one at **Settings > API Keys**
## Installation
Open Claude Code in your project and run:
```
/plugin marketplace add beel-es/claude-plugins
/plugin install beel-api@beel
```
That's it. The skill installs automatically and updates whenever the plugin is updated.
## How it works
Claude Code automatically activates the skill when it detects you are working with the BeeL. API — no manual invocation needed. You can also activate it explicitly:
```
/beel-api
```
Once active, Claude knows:
- The base URL, auth header format, and environment conventions
- That **all POST requests require an `Idempotency-Key`**
- The exact response and error envelope formats
- How to generate fully-typed clients from the live OpenAPI spec
- Where to fetch the always-current docs and spec
## Example prompts
```
Create a typed BeeL. API client using openapi-typescript
```
```
Implement a function that creates an invoice and retries safely on network errors
```
```
Add BeeL invoice creation to my existing Express checkout webhook
```
```
List all ISSUED invoices from the last 30 days and export them to CSV
```
## Machine-readable docs
Claude can fetch these URLs directly during a session to get the latest spec or docs:
| URL | Contents |
|-----|----------|
| [`/llms.txt`](https://docs.beel.es/llms.txt) | Index of all documentation pages |
| [`/llms-full.txt`](https://docs.beel.es/llms-full.txt) | All docs in a single file |
| [`/api/openapi`](https://docs.beel.es/api/openapi) | Full OpenAPI spec (YAML) |
## Further reading
How to get and use your API key
Why every POST needs an idempotency key
---
# BeeL. API
Invoicing API for freelancers and small businesses in Spain with VeriFactu compliance.
import { Callout } from 'fumadocs-ui/components/callout';
## Overview
BeeL. is an invoicing platform built for self-employed professionals (autónomos) and small businesses in Spain. The API lets you programmatically manage the full invoice lifecycle — from creation to payment — with built-in VeriFactu compliance.
| | |
|---|---|
| **Base URL** | `https://app.beel.es/api/v1` |
| **Auth** | API Key via `Authorization: Bearer` header |
| **Format** | JSON (REST) |
| **Environments** | Production (`beel_sk_live_*`) and Sandbox (`beel_sk_test_*`) — same base URL, the key determines the environment |
**Developer Plan required:** Full API access, webhooks, and idempotency support are available exclusively with the [Developer Plan](/pricing). Start with a 7-day free trial.
## Capabilities
Create, issue, send, and manage standard, corrective, and simplified invoices.
Full CRUD with bulk operations, CSV import, and Holded migration.
Reusable product and service catalog for faster invoice creation.
Configure IVA, IGIC, IPSI, IRPF withholding, and equivalence surcharge defaults.
### More Features
Configurable numbering formats with sequential integrity.
Automated submission to the Spanish Tax Agency (AEAT) with cryptographic chaining.
On-demand PDF rendering and direct email delivery to customers.
Auto-generate official invoices from Stripe payments.
Real-time notifications for VeriFactu status updates and more.
Node.js, Java, and Python SDKs with fluent builders and webhook verification.
## Quick Start
```bash
# List your invoices
curl https://app.beel.es/api/v1/invoices \
-H "Authorization: Bearer beel_sk_test_your_key_here"
```
The **Sandbox environment** is a full copy of the API with no real fiscal effects — use it freely for development and testing. Invoices created in Sandbox don't count towards your monthly limit.
All creation endpoints support the `Idempotency-Key` header to prevent duplicates on retries. See the [Idempotency guide](/guides/idempotency) for details.
## Getting Started
1. **[Authentication](/auth)** — Get your API Key and make your first authenticated request
2. **[Pricing](/pricing)** — Choose your Developer Plan tier based on invoice volume
3. **[SDKs](/sdks)** — Use our Node.js, Java, or Python SDKs for faster integration
4. **[Guides](/guides)** — Learn about idempotency, HTTP methods, and fiscal terms
5. **[Webhooks](/webhooks)** — Set up real-time VeriFactu status notifications
## Features
### 🧾 Complete Invoicing
- **Standard invoices** - Regular B2B and B2C invoices
- **Corrective invoices** - Handle refunds and corrections
- **Simplified invoices** - Quick receipts for consumers
- **Recurring invoices** - Schedule automatic invoice generation
- **Multi-series** - Organize invoices by type, client, or project
### 🇪🇸 Spanish Compliance
- **VeriFactu** - Automatic submission to AEAT (optional until 2027)
- **Tax support** - IVA (21%, 10%, 4%, exempt), IGIC (Canary Islands), IPSI (Ceuta/Melilla), IRPF withholding
- **NIF/CIF validation** - Verify Spanish tax IDs automatically
- **Equivalence surcharge** - Recargo de equivalencia for retailers
### 🔧 Developer-Friendly
- **RESTful API** - Predictable, resource-oriented URLs
- **Idempotency** - Safe retries with `Idempotency-Key` header
- **Webhooks** - Real-time notifications for VeriFactu and invoice events
- **SDKs** - Node.js and Java with fluent builders
- **OpenAPI 3.0** - Auto-generate clients in any language
- **Sandbox environment** - Test without affecting production data
### 📊 Data Management
- **Customer database** - Unlimited customers with full address data
- **Product catalog** - Reusable products and services
- **Bulk imports** - CSV upload and Holded migration
- **Custom fields** - Add your own metadata to invoices
### 🚀 Delivery & Exports
- **Professional PDFs** - Auto-generated with your logo and branding
- **Email delivery** - Send invoices directly to customers
- **Download endpoints** - Fetch PDFs via API
- **Advisor exports** - Generate reports for accountants
## Rate Limits
| Limit Type | Endpoints | Rate |
|------------|-----------|------|
| **STANDARD** | CRUD, bulk operations, file uploads | **100 requests/minute** |
| **GLOBAL** | All `/api/*` routes (fallback) | **1,000 requests/minute** |
See the [Pricing page](/pricing#rate-limits) for more details.
## Support
Reach us at **[it@beel.es](mailto:it@beel.es)** — we typically respond within a few hours on business days. Developer Plan users get priority support.
- **Documentation:** This site — Complete API reference and guides
- **SDKs:** [Node.js](/sdks/node), [Java](/sdks/java), and [Python](/sdks/python) with examples
- **Status:** [status.beel.es](https://status.beel.es) — API uptime and incidents
---
# API Pricing
Developer plan pricing, volume tiers, and how billing works for the BeeL. API.
Access to the BeeL. API is available with the **Developer Plan**. It includes everything in the Pro plan plus full API access, webhooks, sandbox environment, and idempotency support.
## How Billing Works
**Only issued invoices in production count.** Drafts, sandbox invoices, and deleted invoices don't count towards your monthly limit. The counter resets on the 1st of each month.
Your bill depends on two things:
1. **Base plan** — The Developer plan starts at 19,90€/month (or 15,90€/month billed annually)
2. **Volume tier** — Choose a tier based on how many invoices you emit per month via the API in production
Sandbox invoices are **completely free and unlimited** — test as much as you need.
## Volume Tiers
All prices exclude VAT. Annual billing saves ~20%.
| Invoices/month | Monthly | Annual (per month) | Annual total |
|---|---|---|---|
| 50 | 19,90€ | 15,90€ | 190,80€ |
| 250 | 32,90€ | 24,90€ | 298,80€ |
| 1.000 | 64,90€ | 49,90€ | 598,80€ |
| 2.500 | 109,90€ | 79,90€ | 958,80€ |
| 5.000 | 164,90€ | 129,90€ | 1.558,80€ |
**Need more than 5.000 invoices/month?** Contact us at [it@beel.es](mailto:it@beel.es) for custom Enterprise pricing.
### What counts as an invoice?
- ✅ **Counts:** Any invoice emitted in the production environment — standard, corrective, simplified, recurring
- ❌ **Doesn't count:** Draft invoices, sandbox invoices
- The limit resets on the **1st of each month**
- If you exceed your tier, you'll be prompted to upgrade before emitting new invoices
## Free Trial
Start with a **7-day free trial**. Credit card required — you won't be charged until the trial ends.
- **Production:** Up to 20 invoices during the trial period
- **Sandbox:** Unlimited invoices — test as much as you need
- Full API access, all webhooks and features enabled
- Cancel anytime during the trial — no charge
## What's Included
All Developer Plan tiers include:
### API & Integration
- **Full REST API** — Complete programmatic access to invoices, customers, products, series, and tax configuration
- **Webhooks** — Real-time notifications for invoice events and VeriFactu status updates
- **Sandbox environment** — Isolated test environment with no fiscal effects
- **Idempotency support** — Safe request retries with `Idempotency-Key` header
- **OpenAPI 3.0 specification** — Auto-generate clients in any language
- **Official SDKs** — [Node.js](/sdks/node), [Java](/sdks/java), and [Python](/sdks/python)
### Invoicing Features (everything in Pro)
- **Electronic invoicing** — VeriFactu compliance with AEAT
- **Professional PDFs** — Automatic generation with customizable templates
- **Email delivery** — Send invoices directly to customers
- **Multiple invoice series** — Organize invoices by type or client
- **Recurring invoices** — Schedule automatic invoice generation
- **Scheduled invoices** — Set future emission dates
- **Corrective invoices** — Handle refunds and corrections
### Data & Support
- **Unlimited customers and products**
- **NIF/CIF validation** — Automatic Spanish tax ID verification
- **Bulk imports** — CSV upload and Holded migration
- **Priority email support** — [it@beel.es](mailto:it@beel.es)
## Rate Limits
API requests are rate-limited per API key:
| Limit Type | Endpoints | Rate |
|------------|-----------|------|
| **STRICT** | Auth, forms, sensitive operations | 5 requests/minute |
| **STANDARD** | CRUD, bulk operations, file uploads | 100 requests/minute |
| **GLOBAL** | All `/api/*` routes (fallback) | 1.000 requests/minute |
See the [Rate Limits guide](/guides/rate-limits) for response headers and best practices. Need higher limits? Contact us at [it@beel.es](mailto:it@beel.es).
## Webhooks
Webhooks are included in all Developer Plan tiers at no additional cost.
**Available events:**
- `invoice.emitted` — Invoice created and finalized
- `invoice.email.sent` — Invoice sent by email
- `invoice.cancelled` — Invoice cancelled
- `verifactu.status.updated` — VeriFactu registration accepted/rejected by AEAT
See the [Webhooks documentation](/webhooks) for setup and payload details.
## Enterprise
Need more than 5.000 invoices/month? We offer:
- **Custom pricing** based on volume
- **Multi-NIF support** — Manage multiple business profiles from one account
- **Dedicated support** with SLA guarantees
- **Custom integrations** and development
Contact us at [it@beel.es](mailto:it@beel.es) to discuss your needs.
## Next Steps
1. **[Start free trial](https://app.beel.es/signup)** — 7 days free
2. **[Set up authentication](/auth)** — Get your API key
3. **[Explore the SDKs](/sdks)** — Node.js, Java, and Python
4. **[Set up webhooks](/webhooks)** — Get real-time notifications
Questions? Email us at [it@beel.es](mailto:it@beel.es).
---
# Glossary
Spanish-English glossary of fiscal and business terms used in the BeeL. API.
The BeeL. API serves self-employed professionals (autónomos) in Spain. Since Spanish tax and invoicing terminology appears throughout the API, this glossary maps each term to its English equivalent and the relevant API fields.
## Tax Terms
| Spanish | English | API Field / Context |
|---------|---------|---------------------|
| IVA (Impuesto sobre el Valor Añadido) | VAT (Value Added Tax) | `TaxType: IVA`, `total_vat` |
| IGIC (Impuesto General Indirecto Canario) | Canary Islands General Indirect Tax | `TaxType: IGIC` |
| IPSI (Impuesto sobre la Producción, Servicios e Importación) | Production, Services & Import Tax (Ceuta & Melilla) | `TaxType: IPSI` |
| IRPF (Impuesto sobre la Renta de las Personas Físicas) | Personal Income Tax Withholding | `default_irpf_rate`, `total_irpf` |
| Recargo de equivalencia | Equivalence surcharge | `default_equivalence_surcharge`, `total_equivalence_surcharge` |
| Base imponible | Taxable base | `taxable_base` |
| Retención | Withholding | `total_irpf`, `irpf_rate` |
| Tipo impositivo | Tax rate | `percentage` |
| Cuota tributaria | Tax amount | `amount` in breakdowns |
| Exento | Exempt | `irpf_exempt`, 0% rates |
| Régimen fiscal | Tax regime | `TaxRegime`, `regime_key` |
| Desglose | Breakdown | `vat_breakdown`, `irpf_breakdown`, `surcharge_breakdown` |
## Invoice Terms
| Spanish | English | API Field / Context |
|---------|---------|---------------------|
| Factura | Invoice | `Invoice` |
| Factura ordinaria | Standard invoice | `type: STANDARD` |
| Factura rectificativa | Corrective invoice | `type: CORRECTIVE` |
| Factura simplificada | Simplified invoice | `type: SIMPLIFIED` |
| Serie de facturación | Invoice series | `series` |
| Número de factura | Invoice number | `invoice_number` |
| Emisor | Issuer | `issuer` |
| Receptor / Destinatario | Recipient | `recipient` |
| Línea de factura | Invoice line item | `lines[]` |
| Forma de pago | Payment method | `payment_method` |
| Fecha de emisión | Issue date | `issue_date` |
| Fecha de vencimiento | Due date | `due_date` |
| Borrador | Draft | `status: DRAFT` |
| Emitida | Issued | `status: ISSUED` |
| Enviada | Sent | `status: SENT` |
| Pagada | Paid | `status: PAID` |
| Vencida | Overdue | `status: OVERDUE` |
| Anulada | Voided / Cancelled | `status: VOIDED` |
| Rectificada | Corrected | `status: RECTIFIED` |
| Programada | Scheduled | `status: SCHEDULED` |
| Factura duplicada | Duplicate invoice | `duplicateInvoice` endpoint |
| Factura recurrente | Recurring invoice | Scheduled invoices with repeat |
## Invoice Status Flow
```
DRAFT → ISSUED → SENT → PAID
│ │ │
│ │ └→ OVERDUE → PAID
│ │
│ └→ PAID (direct)
│
└→ SCHEDULED → DRAFT or ISSUED (on scheduled date)
ISSUED/SENT → VOIDED (via corrective TOTAL)
ISSUED/SENT → RECTIFIED (via corrective PARTIAL)
```
## Payment Methods
| Spanish | English | API Value |
|---------|---------|-----------|
| Transferencia bancaria | Bank transfer | `BANK_TRANSFER` |
| Tarjeta | Card | `CARD` |
| Efectivo | Cash | `CASH` |
| Cheque | Check | `CHECK` |
| Domiciliación bancaria | Direct debit | `DIRECT_DEBIT` |
| Otro | Other | `OTHER` |
## Corrective Invoice Reason Codes
When creating a corrective invoice, you must specify a reason code (`reason`):
| Code | Spanish | English |
|------|---------|---------|
| `R1` | Error fundado en derecho y Art. 80 Uno, Dos y Seis LIVA | Legal error and Art. 80 One, Two and Six LIVA |
| `R2` | Artículo 80 Tres LIVA (Concurso de acreedores) | Article 80 Three LIVA (Bankruptcy proceedings) |
| `R3` | Artículo 80 Cuatro LIVA (Créditos incobrables) | Article 80 Four LIVA (Uncollectable debts) |
| `R4` | Resto de causas | Other causes |
| `R5` | Facturas simplificadas (Art. 80 Uno y Dos LIVA) | Simplified invoices only |
### Corrective Invoice Types
| Type | Spanish | Description |
|------|---------|-------------|
| `PARTIAL` | Rectificación parcial | Partially corrects the original invoice. Original status → `RECTIFIED`. |
| `TOTAL` | Rectificación total | Completely cancels the original invoice. Original status → `VOIDED`. |
## Tax ID Terms
| Spanish | English | Notes |
|---------|---------|-------|
| NIF (Número de Identificación Fiscal) | Tax Identification Number | Umbrella term for all Spanish tax IDs |
| DNI (Documento Nacional de Identidad) | National ID (individuals) | Format: 8 digits + letter (e.g., `12345678A`) |
| NIE (Número de Identidad de Extranjero) | Foreigner ID Number | Format: X/Y/Z + 7 digits + letter (e.g., `X1234567A`) |
| CIF (Código de Identificación Fiscal) | Company Tax ID | Legacy term, now part of NIF |
### Alternative ID Types (Foreign Customers)
For non-Spanish customers without a NIF, use `alternative_id` with one of these types:
| Code | Description |
|------|-------------|
| `02` | VAT-ID (intra-community) |
| `03` | Passport |
| `04` | Country of residence ID |
| `05` | Residence certificate |
| `06` | Other document |
| `07` | Not registered |
## Customer Terms
| Spanish | English | API Field / Context |
|---------|---------|---------------------|
| Cliente | Customer | `Customer` |
| Persona física | Individual | `customer_type: INDIVIDUAL` |
| Persona jurídica | Legal entity | `customer_type: LEGAL_ENTITY` |
| Razón social | Legal name | `legal_name` |
| Nombre comercial | Trade name | `trade_name` |
| Dirección | Address | `address` |
| Código postal | Postal code | `postal_code` |
| Provincia | Province | `province` |
| Desactivado | Deactivated | Soft-deleted customer |
## Product Terms
| Spanish | English | API Field / Context |
|---------|---------|---------------------|
| Producto | Product | `type: PRODUCT` |
| Servicio | Service | `type: SERVICE` |
| Precio unitario | Unit price | `default_price` |
| Unidad | Unit | `unit` |
## Invoice Series Terms
| Spanish | English | API Field / Context |
|---------|---------|---------------------|
| Serie | Series | `series` |
| Código de serie | Series code | `code` |
| Serie por defecto | Default series | `setDefaultSeries` endpoint |
| Reinicio de numeración | Counter reset | `reset_frequency` |
| Reinicio anual | Annual reset | `reset_frequency: ANNUAL` |
| Reinicio mensual | Monthly reset | `reset_frequency: MONTHLY` |
| Sin reinicio | No reset | `reset_frequency: NEVER` |
## VeriFactu & Regulatory Terms
| Spanish | English | Notes |
|---------|---------|-------|
| AEAT (Agencia Estatal de Administración Tributaria) | Spanish Tax Agency | Government entity |
| VeriFactu (Sistema de Facturación Verificable) | Verifiable Invoice System | AEAT's chain-integrity system |
| Registro de facturación | Invoice record | VeriFactu submission |
| Alta | Registration record | New invoice submission |
| Anulación | Cancellation record | Invoice cancellation |
| Huella | Hash / Fingerprint | SHA-256, chain integrity |
| Código QR | QR Code | `qr_url`, `qr_base64` |
| Representación | Representation | Digital signature delegation document |
| Censo de obligados tributarios | Tax registry | AEAT database for NIF validation |
### VeriFactu Statuses
| Status | Spanish | Description |
|--------|---------|-------------|
| `PENDING` | Pendiente | Submitted to AEAT, awaiting response |
| `ACCEPTED` | Aceptado | AEAT accepted the registration |
| `REJECTED` | Rechazado | AEAT rejected the registration |
| `NO_VERIFACTU` | Sin VeriFactu | VeriFactu not configured or not applicable |
### NIF Validation Statuses
| Status | Spanish | Description |
|--------|---------|-------------|
| `VALID` | Válido | NIF exists in the AEAT tax registry |
| `INVALID` | Inválido | NIF not found or invalid format |
| `PENDING` | Pendiente | Validation in progress or AEAT unavailable |
| `NIF_INVALID` | NIF no válido | NIF not valid according to AEAT census (VeriFactu) |
## Tax Regime Keys
These are the `regime_key` values used in VeriFactu submissions.
| Code | Spanish | English |
|------|---------|---------|
| `01` | Régimen general | General regime |
| `02` | Exportación | Export |
| `03` | Bienes usados, arte, antigüedades | Used goods, art, antiques |
| `04` | Oro de inversión | Investment gold |
| `05` | Agencias de viaje | Travel agencies |
| `06` | Grupos de entidades | Group of entities |
| `07` | Criterio de caja | Cash basis |
| `08` | Operaciones IPSI/IVA/IGIC | IPSI/IVA/IGIC operations |
| `09` | Cobros por cuenta de terceros | Mediating agencies |
| `10` | Cobros por cuenta de terceros | Third-party collections |
| `11` | Arrendamiento local | Local rental |
| `14` | IVA pendiente en certificaciones | VAT pending in certifications |
| `15` | IVA pendiente en tracto sucesivo | VAT pending successive tract |
| `17` | OSS e IOSS | OSS and IOSS |
| `18` | Recargo de equivalencia | Equivalence surcharge |
| `19` | REAGYP | Agriculture, livestock & fishing |
| `20` | Régimen simplificado | Simplified regime |
## Webhook Terms
| Term | Description |
|------|-------------|
| Subscription | A registered URL that receives webhook events |
| Event | A notification triggered by an action (e.g., `invoice.emitted`) |
| Delivery | A single HTTP attempt to deliver an event to your URL |
| Secret | HMAC key used to sign and verify webhook payloads |
| Signature | `BeeL-Signature` header with `t=timestamp,v1=hmac` format |
| Retry | Automatic re-delivery after a failed attempt (up to 5 total) |
| Deduplication | Using `BeeL-Event-Id` to prevent processing the same event twice |
---
# HTTP Methods
Complete guide on using GET, POST, PUT and DELETE in the BeeL. API.
The BeeL. API uses standard HTTP methods following REST principles. Each method has a specific purpose and expected behavior.
## Summary
| Method | Purpose | Idempotent | Modifies data |
|--------|---------|------------|---------------|
| GET | Read/query | ✅ Yes | ❌ No |
| POST | Create resources | ❌ No | ✅ Yes |
| PUT | Update resources | ✅ Yes | ✅ Yes |
| DELETE | Remove resources | ✅ Yes | ✅ Yes |
## GET — Read Data
`GET` methods are used to **query** information without modifying any resources.
### Characteristics
- ✅ **Idempotent**: Multiple requests produce the same result
- ✅ **Cacheable**: Responses can be cached
- ❌ **Does not modify data**: Read-only
### Basic Usage
```bash
# Get a specific invoice
curl "https://app.beel.es/api/v1/invoices/{invoice_id}" \
-H "Authorization: Bearer beel_sk_xxx"
```
### Filtering and Pagination
Query parameters are passed in the URL:
```bash
# List invoices with filters
curl "https://app.beel.es/api/v1/invoices?status=ISSUED&limit=10&page=1" \
-H "Authorization: Bearer beel_sk_xxx"
```
### Common Parameters
- `page`: Page number (starts at 1)
- `limit`: Items per page (max 100)
- Endpoint-specific filters (e.g., `status`, `customer_id`)
### Typical Response
```json
{
"success": true,
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "FAC-2025-0001",
...
}
],
"pagination": {
"current_page": 1,
"total_pages": 15,
"total_items": 150,
"items_per_page": 10,
"has_next": true,
"has_previous": false
},
"meta": {
"timestamp": "2025-01-15T10:30:00Z",
"request_id": "123e4567-e89b-12d3-a456-426614174000"
}
}
```
## POST — Create Resources
`POST` methods are used to **create** new resources.
### Characteristics
- ❌ **Not idempotent**: Creating twice generates two different resources
- ✅ **Must use `Idempotency-Key`**: To prevent accidental duplicates
- ✅ **Returns the created resource**
### Basic Usage
```bash
curl -X POST "https://app.beel.es/api/v1/invoices" \
-H "Authorization: Bearer beel_sk_xxx" \
-H "Idempotency-Key: create-invoice-abc123" \
-H "Content-Type: application/json" \
-d '{
"type": "STANDARD",
"issue_date": "2025-01-15",
"recipient": {
"recipient_type": "EXISTING",
"customer_id": "550e8400-e29b-41d4-a716-446655440000"
},
"lines": [
{
"description": "Web development consulting",
"quantity": 40,
"unit": "hours",
"unit_price": 50.00
}
]
}'
```
### Successful Response
```http
HTTP/1.1 201 Created
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": null,
"status": "DRAFT",
...
}
}
```
### Best Practices
1. **Always use `Idempotency-Key`** for resource creation
2. **Validate data** before sending the request
3. **Handle 4xx and 5xx errors** appropriately
4. **Check for 201 Created status** to confirm success
## PUT — Update Resources
`PUT` methods are used to **update** existing resources.
### Characteristics
- ✅ **Idempotent**: Multiple updates with the same data produce the same result
- ✅ **Partial update**: Only send the fields you want to change
- ⚠️ **Requires resource ID** in the URL
### Basic Usage
```bash
curl -X PUT "https://app.beel.es/api/v1/customers/{customer_id}" \
-H "Authorization: Bearer beel_sk_xxx" \
-H "Idempotency-Key: update-customer-456" \
-H "Content-Type: application/json" \
-d '{
"email": "new-email@example.com",
"phone": "+34912345678"
}'
```
### Partial Update
You only need to send the fields you want to modify:
```json
{
"email": "new@example.com"
}
```
Fields not included remain unchanged.
### Successful Response
```http
HTTP/1.1 200 OK
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"legal_name": "Company SL",
"email": "new-email@example.com",
"phone": "+34912345678",
...
}
}
```
### Restrictions
Some resources have **update restrictions**:
- **Invoices**: Can only update invoices in `DRAFT` status
- **Series**: Cannot change the code once created
- **Customers**: Cannot change NIF if they have associated invoices
## DELETE — Remove Resources
`DELETE` methods are used to **delete** or **deactivate** resources.
### Characteristics
- ✅ **Idempotent**: Deleting an already deleted resource returns the same result
- ⚠️ **Soft delete**: Most resources are marked as "deleted" but not physically removed
- ⚠️ **May have restrictions**: Some resources cannot be deleted if they have dependencies
### Basic Usage
```bash
curl -X DELETE "https://app.beel.es/api/v1/customers/{customer_id}" \
-H "Authorization: Bearer beel_sk_xxx"
```
### Successful Response
```http
HTTP/1.1 204 No Content
```
Or with confirmation message:
```http
HTTP/1.1 200 OK
{
"success": true,
"data": {
"message": "Customer deleted successfully"
}
}
```
### Soft Delete
Most resources use **soft delete**:
- Resource is marked as inactive
- Does not appear in default listings
- Data is preserved for audit purposes
- Cannot be restored via API (contact support)
### Common Restrictions
You cannot delete:
- **Customers with associated invoices**
- **Invoice series with invoices**
- **The default series**
- **Issued invoices** (use void instead)
## HTTP Status Codes
### Success (2xx)
- `200 OK`: Successful request (GET, PUT, DELETE)
- `201 Created`: Resource created successfully (POST)
- `204 No Content`: Successful deletion with no response content
### Client Errors (4xx)
- `400 Bad Request`: Invalid data
- `401 Unauthorized`: Missing or invalid API Key
- `403 Forbidden`: You don't have permissions for this operation
- `404 Not Found`: Resource not found
- `409 Conflict`: Conflict (e.g., duplicate, business rule restriction)
- `422 Unprocessable Entity`: Business validation failed
- `429 Too Many Requests`: Rate limit exceeded
### Server Errors (5xx)
- `500 Internal Server Error`: Internal server error
- `503 Service Unavailable`: Service temporarily unavailable
## Important Headers
### Requests
```http
Authorization: Bearer beel_sk_xxx # Authentication (required)
Idempotency-Key: unique-key-123 # Idempotency (recommended for POST/PUT)
Content-Type: application/json # Content type (for POST/PUT)
```
### Responses
```http
Idempotency-Replay: true # Indicates cached response
X-RateLimit-Limit: 100 # Request limit
X-RateLimit-Remaining: 95 # Remaining requests
X-RateLimit-Reset: 1642089600 # Reset timestamp
```
## Examples by Resource
### Invoices
```bash
# Create
POST /v1/invoices
# List
GET /v1/invoices
# Get one
GET /v1/invoices/{invoice_id}
# Update (DRAFT only)
PUT /v1/invoices/{invoice_id}
# Delete (DRAFT only)
DELETE /v1/invoices/{invoice_id}
# Issue
POST /v1/invoices/{invoice_id}/issue
# Void
POST /v1/invoices/{invoice_id}/void
```
### Customers
```bash
# Create
POST /v1/customers
# List
GET /v1/customers
# Get one
GET /v1/customers/{customer_id}
# Update
PUT /v1/customers/{customer_id}
# Deactivate
DELETE /v1/customers/{customer_id}
```
### Products
```bash
# Create
POST /v1/products
# List
GET /v1/products
# Search (autocomplete)
GET /v1/products/search?q=consulting
# Get one
GET /v1/products/{product_id}
# Update
PUT /v1/products/{product_id}
# Delete
DELETE /v1/products/{product_id}
```
## Next Steps
- [Idempotency](/guides/idempotency) — Implement idempotency keys
- [Create invoice](/invoices/createInvoice) — Practical POST example
- [List invoices](/invoices/listInvoices) — Practical GET example
---
# Idempotency
How to use idempotency keys to prevent duplicate operations in the BeeL. API.
## What is Idempotency?
Idempotency ensures that an operation can be executed multiple times with the same result. In APIs, this is crucial to avoid creating duplicate resources when there are network issues or application errors.
## How it Works
BeeL. implements idempotency via the standard `Idempotency-Key` header. When you include this header in write requests (POST, PUT), the API:
1. Stores the idempotency key along with the operation result
2. If it receives the same request with the same key, returns the stored result
3. Does not execute the operation again
This prevents duplicate invoices, customers, or other resources even if your application retries the request.
## Recommended Usage
### POST Requests (creation)
**Always** use `Idempotency-Key` when creating resources:
```bash
curl -X POST "https://app.beel.es/api/v1/invoices" \
-H "Authorization: Bearer beel_sk_xxx" \
-H "Idempotency-Key: invoice-order-12345" \
-H "Content-Type: application/json" \
-d '{
"type": "STANDARD",
"issue_date": "2025-01-15",
"recipient": {
"recipient_type": "EXISTING",
"customer_id": "550e8400-e29b-41d4-a716-446655440000"
},
"lines": [
{
"description": "Consulting",
"quantity": 1,
"unit_price": 100.00
}
]
}'
```
### PUT Requests (update)
Also recommended for critical updates:
```bash
curl -X PUT "https://app.beel.es/api/v1/customers/{customer_id}" \
-H "Authorization: Bearer beel_sk_xxx" \
-H "Idempotency-Key: update-client-address-456" \
-H "Content-Type: application/json" \
-d '{
"address": {
"street": "New address 123",
"number": "45",
"postal_code": "28001",
"city": "Madrid",
"province": "Madrid",
"country": "España"
}
}'
```
**Developer Plan exclusive:** Idempotency support is available only with the Developer Plan. See [Pricing](/pricing) for details.
## Key Generation
The idempotency key must be **unique** for each logical operation you want to perform.
### ✅ Best Practices
```javascript
// Use UUID v4
import { v4 as uuidv4 } from 'uuid';
const idempotencyKey = uuidv4(); // "550e8400-e29b-41d4-a716-446655440000"
// Combine identifiers from your system
const idempotencyKey = `invoice-order-${orderId}-${timestamp}`;
// Use external references
const idempotencyKey = `sync-shopify-order-${shopifyOrderId}`;
// Hash-based (deterministic for same input)
import crypto from 'crypto';
const idempotencyKey = crypto
.createHash('sha256')
.update(JSON.stringify({ orderId, customerId }))
.digest('hex');
```
### ❌ Bad Practices
```javascript
// DON'T use values that repeat across different operations
const idempotencyKey = 'create-invoice'; // ❌ Too generic, will collide
// DON'T use timestamps (can collide in high-traffic scenarios)
const idempotencyKey = Date.now().toString(); // ❌ Not unique enough
// DON'T use random values (can't retry with same key)
const idempotencyKey = Math.random().toString(); // ❌ Non-deterministic
```
## Usage Scenarios
### Problem: Network Error
**Without idempotency:**
```
1. Client sends request → Timeout (no response)
2. Client retries → Creates second invoice ❌
3. Result: Duplicate invoices, angry customer
```
**With idempotency:**
```
1. Client sends request with key "abc123" → Timeout
2. Client retries with same key "abc123" → API detects duplicate
3. Result: Returns original invoice ✅
```
### Problem: Automatic Retry Logic
```javascript
// ❌ Without idempotency - DANGER
async function createInvoice(data) {
try {
return await api.post('/v1/invoices', data);
} catch (error) {
if (error.code === 'NETWORK_ERROR') {
return await api.post('/v1/invoices', data); // Creates duplicate!
}
}
}
// ✅ With idempotency - SAFE
async function createInvoice(data, idempotencyKey) {
const headers = {
'Authorization': `Bearer ${process.env.BEEL_API_KEY}`,
'Idempotency-Key': idempotencyKey
};
try {
return await api.post('/v1/invoices', data, { headers });
} catch (error) {
if (error.code === 'NETWORK_ERROR') {
// Same key ensures we get the original response
return await api.post('/v1/invoices', data, { headers }); // ✅ Safe
}
}
}
```
### Problem: Concurrent Requests
```javascript
// ✅ Multiple systems creating the same logical invoice
// (e.g., Shopify + manual ERP sync)
// System A
await createInvoice(invoiceData, `shopify-order-${orderId}`);
// System B (runs concurrently)
await createInvoice(invoiceData, `shopify-order-${orderId}`);
// Result: Only ONE invoice is created ✅
// Second request returns the first invoice
```
## Lifetime
Idempotency keys are stored for **24 hours**. After this time:
- The key can be reused for a new operation
- Attempting to retry with the same key will create a new resource
**24-hour limit:** If you need to retry a failed operation after 24 hours, generate a new idempotency key.
## Response Behavior
### First Request (successful)
```http
HTTP/1.1 201 Created
Content-Type: application/json
Idempotency-Replay: false
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "FAC-2025-0001",
"status": "DRAFT",
...
}
}
```
### Duplicate Request (with same key)
```http
HTTP/1.1 200 OK
Content-Type: application/json
Idempotency-Replay: true
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "FAC-2025-0001",
"status": "DRAFT",
...
}
}
```
**Note:** The `Idempotency-Replay: true` header indicates the response comes from a previous request. The status code may be `200 OK` instead of `201 Created`.
## Error Handling
If the original request failed, retrying with the same key will:
- **Return the original error** (if it was a 4xx client error)
- **Retry the operation** (if it was a 5xx server error or timeout)
```javascript
// First request fails with validation error
try {
await createInvoice(invalidData, 'key-123');
} catch (error) {
// 422 Unprocessable Entity
console.log(error.status); // 422
}
// Retrying with same key returns the SAME error
try {
await createInvoice(invalidData, 'key-123');
} catch (error) {
// Same 422 error (from cache)
console.log(error.status); // 422
console.log(error.headers['idempotency-replay']); // 'true'
}
```
To fix the error, you must either:
1. **Wait 24 hours** for the key to expire
2. **Use a different key** (recommended)
## Limitations
| Aspect | Limit |
|--------|-------|
| **Lifetime** | 24 hours |
| **Max length** | 255 characters |
| **Applies to** | POST and PUT requests only |
| **Does NOT apply to** | GET, DELETE (naturally idempotent) |
| **Availability** | Developer Plan only |
## Official SDK Support
Our official SDKs (coming soon) will **auto-generate idempotency keys** on every creation request. You won't need to do anything — duplicate protection will work out of the box.
### Automatic (default behavior)
Every `create()` call automatically generates a UUID idempotency key:
```typescript
// Node.js — idempotency key auto-generated (crypto.randomUUID())
const invoice = await beel.invoices.create(invoiceData);
```
```java
// Java — idempotency key auto-generated (UUID.randomUUID())
Invoice invoice = beel.invoices().create(invoiceData);
```
```python
# Python — idempotency key auto-generated (uuid.uuid4())
invoice = beel.invoices.create(invoice_data)
```
### Custom key (optional override)
If you want to use your own key (e.g., to safely retry from your system), pass it as a second argument:
```typescript
// Node.js — use your own key
const invoice = await beel.invoices.create(invoiceData, `order-${orderId}`);
```
```java
// Java — use your own key
Invoice invoice = beel.invoices().create(invoiceData, UUID.fromString(myKey));
```
```python
# Python — use your own key
invoice = beel.invoices.create(invoice_data, idempotency_key=f"order-{order_id}")
```
### Which methods support idempotency?
| Method | Java | TypeScript | Python |
|--------|------|------------|--------|
| `invoices.create()` | ✅ | ✅ | ✅ |
| `invoices.createCorrective()` | ✅ | ✅ | ✅ |
| `products.create()` | ✅ | ✅ | ✅ |
| `products.createBulk()` | ✅ | ✅ | ✅ |
All of these auto-generate a UUID if you don't provide one.
## Best Practices Summary
✅ **Do:**
- Use UUIDs or hash-based keys for uniqueness
- Include idempotency keys in ALL POST/PUT requests
- Store the key alongside the request in your database
- Retry with the SAME key on network errors
- Use descriptive key names for debugging (e.g., `invoice-shopify-order-${id}`)
❌ **Don't:**
- Use generic or repeated values (`'create-invoice'`)
- Generate random keys that can't be reproduced
- Rely solely on timestamps (can collide)
- Forget to implement retries with the same key
- Use idempotency keys longer than 255 characters
## Real-World Example
Complete example with proper error handling:
```typescript
import { v4 as uuidv4 } from 'uuid';
async function createInvoiceWithRetry(invoiceData: InvoiceData, maxRetries = 3) {
const idempotencyKey = uuidv4();
let attempt = 0;
while (attempt < maxRetries) {
try {
const response = await fetch('https://app.beel.es/api/v1/invoices', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.BEEL_API_KEY}`,
'Idempotency-Key': idempotencyKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(invoiceData)
});
if (!response.ok) {
// Client errors (4xx) - don't retry
if (response.status >= 400 && response.status < 500) {
throw new Error(`Validation error: ${await response.text()}`);
}
// Server errors (5xx) - retry
throw new Error(`Server error: ${response.status}`);
}
const result = await response.json();
const isReplay = response.headers.get('idempotency-replay') === 'true';
console.log(isReplay ? 'Returned cached invoice' : 'Created new invoice');
return result.data;
} catch (error) {
attempt++;
if (attempt >= maxRetries) throw error;
// Exponential backoff
await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 1000));
}
}
}
// Usage
try {
const invoice = await createInvoiceWithRetry({
type: 'STANDARD',
issue_date: '2025-01-15',
recipient: { recipient_type: 'EXISTING', customer_id: customerId },
lines: [{ description: 'Service', quantity: 1, unit_price: 100 }]
});
console.log('Invoice created:', invoice.invoice_number);
} catch (error) {
console.error('Failed to create invoice:', error);
}
```
## Next Steps
- **[HTTP Methods Guide](/guides/http-methods)** — Learn about GET, POST, PUT, DELETE
- **[Create an invoice](/invoices/createInvoice)** — Practical API reference
- **[Official SDKs](/sdks)** — Coming soon, with built-in idempotency support
Questions? Email us at [it@beel.es](mailto:it@beel.es).
---
# Rate Limits
Understand the rate limits applied to the BeeL API and how to handle them.
import { Callout } from 'fumadocs-ui/components/callout';
The BeeL API enforces rate limits to protect service stability. Limits are applied **per client** (identified by API key or IP address) within a **60-second rolling window**.
## Tiers
| Tier | Limit | Period | Applied to |
|------|-------|--------|------------|
| **Standard** | 100 requests | 60 seconds | All resource endpoints |
| **Global** | 1,000 requests | 60 seconds | All `/api` endpoints combined |
All limits apply simultaneously. A request to `/api/v1/invoices` counts against both the **Standard** tier (100/min) and the **Global** tier (1,000/min).
## Rate-Limited Endpoints
### Standard (100 req/min)
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/v1/invoices/**` | ANY | All invoice operations (CRUD, bulk, PDF, email) |
| `/api/v1/customers/**` | ANY | All customer operations (CRUD, bulk) |
| `/api/v1/nif/validate` | POST | NIF/CIF validation |
| `/api/v1/subscriptions/checkout` | POST | Subscription checkout |
| `/api/v1/public/metrics` | GET | Public metrics |
| `/api/v1/me` | ANY | Profile operations |
| `/api/v1/me/logo` | POST | Logo upload |
| `/api/v1/companies/{id}/representation/generate` | POST | Generate representation document |
| `/api/v1/companies/{id}/representation/submit` | POST | Submit representation document |
### Global (1,000 req/min)
Applied to **all** `/api` requests regardless of endpoint. This is a safety net to prevent any single client from overwhelming the system.
## Client Identification
Rate limits are tracked per client:
- **API key users** → identified by the `Bearer beel_sk_...` token
- **Browser/anonymous users** → identified by IP address
Each client has its own independent quota for each tier.
## Excluded Endpoints
| Endpoint | Reason |
|----------|--------|
| `/api/webhooks/stripe` | Stripe signs webhook requests; rejecting them causes retries |
## Response Headers
When a rate limit is hit, the API returns `429 Too Many Requests` with these headers:
```http
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 60
```
```json
{
"error": "Rate limit exceeded. Try again in a minute."
}
```
| Header | Description |
|--------|-------------|
| `Retry-After` | Seconds to wait before retrying |
| `RateLimit-Limit` | Maximum requests allowed in the window |
| `RateLimit-Remaining` | Requests remaining in the current window |
| `RateLimit-Reset` | Seconds until the window resets |
## Handling Rate Limits
### Retry with backoff
```typescript
async function requestWithRetry(fn: () => Promise, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429) {
const retryAfter = parseInt(error.headers?.['retry-after'] || '60');
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
throw error;
}
}
throw new Error('Max retries exceeded');
}
```
### Best practices
- **Use bulk endpoints** when operating on multiple resources — one bulk request instead of N individual requests
- **Cache responses** where possible to avoid unnecessary API calls
- **Respect `Retry-After`** headers instead of retrying immediately
- **Use idempotency keys** so retried requests don't create duplicates
## API Status
Check [status.beel.es](https://status.beel.es) for real-time API uptime, incident reports, and scheduled maintenance.
## Need Higher Limits?
If the standard limits don't fit your use case, contact us and we'll work out a plan:
📧 **Request a rate limit increase →**
---
# SDKs
Official SDKs to integrate BeeL in your application — coming soon.
---
# Java SDK
Java SDK for the BeeL API — coming soon.
---
# Node.js / TypeScript SDK
TypeScript SDK for the BeeL API — coming soon.
---
# Python SDK
Python SDK for the BeeL API — coming soon.
---
# How Taxes Are Applied
What taxes BeeL uses in invoices generated from Stripe and where to configure them.
## At a Glance
| | |
|---|---|
| **What taxes are used** | The ones configured in your BeeL account (IVA/IGIC/IPSI + IRPF if applicable) |
| **Does it use Stripe tax rates?** | No. BeeL always uses your tax configuration, not Stripe's |
| **Where to change them** | Settings > Taxes in BeeL (see below) |
| **Does it affect already issued invoices?** | No. Only new ones |
---
## How does it work?
When BeeL generates an invoice from a Stripe payment, **it uses your default tax configuration**. It doesn't matter what you have set up in Stripe — BeeL ignores it.
This means:
- Your **main tax** (IVA, IGIC, or IPSI) is applied at the percentage you've chosen
- If you have **IRPF** enabled, it's applied automatically
- If you have **recargo de equivalencia** (equivalence surcharge), it's included as well
### Example
If your configuration is IVA 21% + IRPF 15%, and you receive a payment of **100 EUR** in Stripe:
| Item | Amount |
|----------|---------|
| Taxable base | 100.00 EUR |
| IVA (21%) | +21.00 EUR |
| IRPF (15%) | -15.00 EUR |
| **Total** | **106.00 EUR** |
---
## Where do I configure taxes?
1. Go to **Settings > Taxes** in BeeL
2. Choose your **main tax** (IVA, IGIC, or IPSI) and the percentage
3. Enable **IRPF** if it applies to you
4. Enable **recargo de equivalencia** (equivalence surcharge) if applicable
These values will be used in all automatic invoices.
If you need a different tax for a specific invoice, you can edit it manually after BeeL generates it.
---
## FAQ
### Why doesn't BeeL use Stripe's taxes?
Because Stripe doesn't manage taxes according to Spanish tax regulations. BeeL applies your local configuration to ensure invoices are VeriFactu compliant.
### What happens if I change my taxes?
Changes apply to **new invoices only**. Already issued invoices remain unchanged.
### Can I have different taxes per customer?
Automatic invoicing always uses your default configuration. If a customer needs something different (for example, IGIC instead of IVA), you can edit the invoice manually after it's generated.
---
# Configure Proforma Invoices in Stripe
Set up Stripe invoices as proforma so the official ones are generated by BeeL.
## At a Glance
| | |
|---|---|
| **Why do this** | So your customers don't receive two invoices (one from Stripe and one from BeeL) |
| **What you do** | Mark Stripe invoices as "PROFORMA" and disable their emails |
| **Consequence** | Your customers won't see invoices in the Stripe portal — the official ones are in BeeL |
| **Time** | 5 minutes |
---
## Why is this necessary?
When you connect Stripe with BeeL, there are **two systems generating documents**:
- **Stripe** generates its own receipts/invoices — **they have no fiscal validity in Spain**
- **BeeL** generates official invoices — **VeriFactu compliant**
If you don't do anything, your customer may receive two documents and not know which one is valid. The solution is simple: mark Stripe's as proforma and let BeeL handle the official ones.
**Current limitation:** by disabling Stripe invoices, your customers won't be able to view them in the Stripe Customer Portal. This is the only way to avoid duplicates and ensure invoices comply with regulations. We're working to improve this.
---
## Step by Step
### 1. Add a "PROFORMA" prefix to Stripe invoices
1. Go to the [Stripe Dashboard](https://dashboard.stripe.com)
2. Navigate to **Settings > Billing > Invoice template**
3. In the **Prefix** field, type `PROFORMA-`
4. Save your changes
Now Stripe invoices will be numbered as `PROFORMA-0001`, `PROFORMA-0002`... making it clear they're not fiscal documents.
### 2. Add an informational note
In the same **Invoice template** section:
1. Find the **Footer** or **Memo** field
2. Add this text:
> This document is for informational purposes only and has no fiscal validity. The official invoice will be issued by BeeL in compliance with VeriFactu regulations.
### 3. Disable Stripe invoice emails
So your customers only receive invoices from BeeL:
1. Go to **Settings > Billing > Emails**
2. Disable **Email invoices and receipts to customers**
3. Save your changes
If you want Stripe to keep sending **payment receipts** (payment confirmation), you can keep receipts enabled and only disable invoices.
### 4. Disable invoices in the Customer Portal
If you use the Stripe Customer Portal:
1. Go to **Settings > Billing > Customer portal**
2. Under **Invoice history**, disable visibility
3. Save your changes
---
## Result
With this configuration:
- Your customers **only receive official invoices** from BeeL
- Stripe invoices are marked as **PROFORMA** for your internal use
- **No duplicates** or confusion
- You comply with **VeriFactu** through BeeL
---
# Overview
Connect your Stripe account with BeeL to automatically generate official invoices with every payment.
## At a Glance
| | |
|---|---|
| **What it does** | Generates an official invoice in BeeL every time you receive a payment in Stripe |
| **How it connects** | Via [Stripe Connect](https://stripe.com/connect) (OAuth) |
| **What you need** | A Stripe account and an active BeeL subscription |
| **What you should know** | Stripe invoices are not the official ones — BeeL invoices are (VeriFactu compliant) |
---
## How does it work?
BeeL connects to your Stripe account using **Stripe Connect**. This means you authorize BeeL to receive notifications about your payments, without sharing your API keys or sensitive data.
### The flow is simple
1. **Your customer pays** in Stripe (subscription, one-time payment, anything)
2. **Stripe notifies BeeL** automatically via a webhook
3. **BeeL generates the official invoice** using your tax configuration (IVA, IRPF, series...)
4. **Your customer receives the invoice** by email (if enabled)
You don't have to do anything. Just connect and configure once.
---
## What does this mean for my customers?
This is important and we want to be transparent:
**Stripe invoices and BeeL invoices are different things.** Stripe generates its own payment documents, but they don't comply with Spanish tax regulations (VeriFactu). The official invoices are the ones generated by BeeL.
To avoid confusion, we recommend **configuring Stripe invoices as proforma** and disabling their invoicing emails. That way your customers only receive the official invoices from BeeL.
The downside is that **your customers won't be able to see invoices in the Stripe portal**. This is a current limitation — official invoices are in BeeL, not in Stripe. We're working to improve this experience, but for now it's the only way to ensure invoices are VeriFactu compliant.
---
## Initial Setup
1. Go to **Settings > Integrations** in BeeL
2. Click **Connect** on the Stripe card
3. Authorize the connection with your Stripe account (Stripe Connect opens)
4. Open the Stripe configuration and choose your invoice series, whether to send emails, etc.
That's it. From that point on, every payment generates an invoice automatically.
---
## Step-by-Step Guides
How to disable Stripe invoices so they don't interfere with the official ones from BeeL.
What taxes BeeL uses in automatic invoices and where to change them.
---
# Deduplication
Safely handle duplicate webhook deliveries using the BeeL-Event-Id header.
Network issues and retries mean your endpoint **may receive the same event more than once**. BeeL. provides two mechanisms to help you deduplicate deliveries safely.
## The `BeeL-Event-Id` Header
Every delivery attempt for the same logical event carries the **same `BeeL-Event-Id` UUID**, regardless of how many times BeeL has tried. This value matches the `id` field in the JSON payload.
```
BeeL-Event-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
BeeL-Delivery-Id: 8ee6b023-c4e5-482e-93ca-dc66da2f9cb5
Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
```
- **`BeeL-Event-Id`** — Identifies the logical event. Same across all retries.
- **`BeeL-Delivery-Id`** — Identifies this specific HTTP attempt. Unique per call. Matches the `id` in the delivery log.
- **`Idempotency-Key`** — Same value as `BeeL-Event-Id`, included for framework compatibility.
Use `BeeL-Event-Id` for deduplication (same across retries). Use `BeeL-Delivery-Id` to correlate with specific delivery log entries in the dashboard.
## How to Deduplicate
Store the `BeeL-Event-Id` value the first time you process an event successfully and discard subsequent deliveries with the same ID.
### Node.js with Redis
```javascript
app.post('/webhooks/beel', express.raw({ type: 'application/json' }), async (req, res) => {
if (!verifyBeelSignature(req.body, req.headers['BeeL-Signature'], SECRET)) {
return res.status(401).send('Unauthorized');
}
const eventId = req.headers['beel-event-id'];
const event = JSON.parse(req.body.toString());
// Check for duplicate
const alreadyProcessed = await redis.exists(`webhook:${eventId}`);
if (alreadyProcessed) {
return res.status(200).send('Already processed');
}
await handleEvent(event);
// Mark as processed — keep for 7 days
await redis.setEx(`webhook:${eventId}`, 7 * 24 * 60 * 60, '1');
res.status(200).send('OK');
});
```
### Python with a database
```python
@app.post("/webhooks/beel")
async def webhook(request: Request):
raw_body = await request.body()
event_id = request.headers.get("beel-event-id")
if not verify_beel_signature(raw_body, request.headers.get("BeeL-Signature"), SECRET):
raise HTTPException(status_code=401)
# Check duplicate
if await db.processed_webhooks.find_one({"event_id": event_id}):
return {"ok": True}
event = json.loads(raw_body)
await handle_event(event)
await db.processed_webhooks.insert_one({
"event_id": event_id,
"processed_at": datetime.utcnow()
})
return {"ok": True}
```
## Server-Side Deduplication
BeeL also deduplicates on its end: if a delivery has already succeeded for a given `BeeL-Event-Id`, BeeL will not re-enqueue it for automatic retry even if the outbox processes the event more than once.
Combined with your own `BeeL-Event-Id` check, this gives you **end-to-end exactly-once processing**.
## Best Practices
- **Always deduplicate** — never assume an event arrives exactly once
- **Acknowledge first, process later** — return `200 OK` immediately and handle the event in a background job
- **Make your handlers idempotent** — even if a duplicate slips through, applying the same state change twice should be safe
```javascript
// ✅ Idempotent: setting a field is safe to repeat
async function handleVeriFactuUpdate(data) {
await db.invoices.updateOne(
{ _id: data.invoice_id },
{ $set: { verifactu_status: data.new_status, qr_url: data.qr_url } }
);
}
// ❌ Not idempotent: inserting without a duplicate check creates duplicates
async function handleVeriFactuUpdate(data) {
await db.audit_logs.insertOne({ invoice_id: data.invoice_id, status: data.new_status });
}
```
---
For general API idempotency (preventing duplicate resource creation via `Idempotency-Key`), see [Idempotency](/guides/idempotency).
---
# Events
All webhook event types and their payload schemas.
BeeL. sends webhook events when key things happen in your account. Each event has a `type` field that identifies what occurred, and a `data` object with event-specific details.
**All field names use `snake_case`** — both in the envelope and in `data` payloads.
## Envelope Structure
Every webhook delivery follows the same envelope format:
```json
{
"id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"type": "invoice.emitted",
"created_at": "2026-03-17T22:30:20.085Z",
"api_version": "2025-01",
"livemode": true,
"data": { ... }
}
```
| Field | Type | Description |
|-------|------|-------------|
| `id` | `string` (UUID) | Unique identifier for this webhook event. |
| `type` | `string` | Event type (see below). |
| `created_at` | `string` (ISO 8601) | Timestamp when the event was created. |
| `api_version` | `string` | API version used to generate the payload. |
| `livemode` | `boolean` | `true` for production, `false` for sandbox. |
| `data` | `object` | Event-specific payload (see below). |
Test payloads include an additional `"test": true` field and always have `"livemode": false`.
---
## Available Events
| Event type | Description |
|------------|-------------|
| [`invoice.emitted`](#invoiceemitted) | An invoice was emitted (created and finalized) |
| [`invoice.email.sent`](#invoiceemailsent) | An invoice was successfully sent by email |
| [`invoice.cancelled`](#invoicecancelled) | An invoice was cancelled (anulada) |
| [`verifactu.status.updated`](#verifactustatusupdated) | AEAT processed a VeriFactu registration — accepted or rejected |
---
## `invoice.emitted`
Fired when an invoice is emitted (created and finalized).
### Payload
```json
{
"id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"type": "invoice.emitted",
"created_at": "2026-03-17T22:30:20.085Z",
"api_version": "2025-01",
"livemode": true,
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "A-2026-0026",
"customer_email": "john@example.com",
"customer_name": "John Doe"
}
}
```
### `data` fields
| Field | Type | Description |
|-------|------|-------------|
| `invoice_id` | `string` (UUID) | The emitted invoice. |
| `invoice_number` | `string` | Human-readable invoice number (e.g. `A-2026-0026`). |
| `customer_email` | `string` | Customer's email address. |
| `customer_name` | `string` | Customer's name. |
---
## `invoice.email.sent`
Fired when an invoice has been successfully sent by email.
### Payload
```json
{
"id": "4a8b2c3d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
"type": "invoice.email.sent",
"created_at": "2026-03-17T22:30:20.085Z",
"api_version": "2025-01",
"livemode": true,
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "A-2026-0026",
"all_recipients": ["john@example.com", "accounting@example.com"],
"sent_at": "2026-03-17T22:30:20.050725Z"
}
}
```
### `data` fields
| Field | Type | Description |
|-------|------|-------------|
| `invoice_id` | `string` (UUID) | The invoice that was sent. |
| `invoice_number` | `string` | Human-readable invoice number. |
| `all_recipients` | `string[]` | All email addresses the invoice was sent to. |
| `sent_at` | `string` (ISO 8601) | Timestamp when the email was sent. |
---
## `invoice.cancelled`
Fired when an invoice is cancelled (anulada).
### Payload
```json
{
"id": "5b9c3d4e-6f7a-8b9c-0d1e-2f3a4b5c6d7e",
"type": "invoice.cancelled",
"created_at": "2026-03-17T22:31:15.000Z",
"api_version": "2025-01",
"livemode": true,
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "A-2026-0026",
"cancellation_reason": "Error en los datos del cliente"
}
}
```
### `data` fields
| Field | Type | Description |
|-------|------|-------------|
| `invoice_id` | `string` (UUID) | The cancelled invoice. |
| `invoice_number` | `string` | Human-readable invoice number. |
| `cancellation_reason` | `string` | Reason provided for the cancellation. |
---
## `verifactu.status.updated`
Fired when the VeriFactu registration status changes. This includes:
- Initial submission (status: `PENDING`)
- Final acceptance by AEAT (status: `ACCEPTED`)
- Rejection by AEAT (status: `REJECTED`)
### Payload
```json
{
"id": "6c0d4e5f-7a8b-9c0d-1e2f-3a4b5c6d7e8f",
"type": "verifactu.status.updated",
"created_at": "2026-03-07T16:20:26Z",
"api_version": "2025-01",
"livemode": true,
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "2025-001",
"verifactu_registration_id": "660e8400-e29b-41d4-a716-446655440001",
"previous_status": "PENDING",
"new_status": "ACCEPTED",
"qr_url": "https://sede.agenciatributaria.gob.es/Sede/verifactu?id=ABC123XYZ",
"qr_base64": "iVBORw0KGgoAAAANSUhEUgAAAMg...",
"invoice_hash": "B11F3A015173AD99075E2720F61E2DE1FF08CBFEDD85C6F73C77AD835301B2A3",
"error_code": null,
"error_message": null
}
}
```
### `data` fields
| Field | Type | Description |
|-------|------|-------------|
| `invoice_id` | `string` (UUID) | The invoice that was registered with VeriFactu. |
| `invoice_number` | `string` \| `null` | Human-readable invoice number (e.g. `2025-001`). |
| `verifactu_registration_id` | `string` (UUID) | The VeriFactu registration record in BeeL. |
| `previous_status` | `string` \| `null` | Status before this update. `null` on first submission. |
| `new_status` | `string` | Status after this update. |
| `qr_url` | `string` \| `null` | AEAT verification URL. Available from `PENDING` status onwards. |
| `qr_base64` | `string` \| `null` | QR code as base64-encoded PNG. Embed in invoice PDFs. |
| `invoice_hash` | `string` \| `null` | SHA-256 hash of the VeriFactu record. Present only when `ACCEPTED`. |
| `error_code` | `string` \| `null` | AEAT error code when `new_status` is `REJECTED` or `ACCEPTED_WITH_ERRORS`. |
| `error_message` | `string` \| `null` | Human-readable error description from AEAT. |
Null fields are omitted from the JSON payload.
### Status values
| Status | Meaning |
|--------|---------|
| `PENDING` | BeeL. has submitted to AEAT and is waiting for a response. |
| `ACCEPTED` | AEAT accepted the registration. `qr_url`, `qr_base64`, and `invoice_hash` are populated. |
| `ACCEPTED_WITH_ERRORS` | AEAT accepted with warnings. Check `error_code` and `error_message`. |
| `REJECTED` | AEAT rejected the registration. Check `error_code` and `error_message`. |
| `AEAT_SERVER_ERROR` | AEAT's server failed. BeeL. will retry automatically. |
### Accepted example
```json
{
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "2025-001",
"verifactu_registration_id": "660e8400-e29b-41d4-a716-446655440001",
"previous_status": "PENDING",
"new_status": "ACCEPTED",
"qr_url": "https://sede.agenciatributaria.gob.es/Sede/verifactu?id=ABC123XYZ",
"qr_base64": "iVBORw0KGgoAAAANSUhEUgAAAMg...",
"invoice_hash": "B11F3A015173AD99075E2720F61E2DE1FF08CBFEDD85C6F73C77AD835301B2A3"
}
}
```
### Rejected example
```json
{
"data": {
"invoice_id": "550e8400-e29b-41d4-a716-446655440000",
"invoice_number": "2025-001",
"verifactu_registration_id": "660e8400-e29b-41d4-a716-446655440001",
"previous_status": "PENDING",
"new_status": "REJECTED",
"error_code": "1105",
"error_message": "NIF del emisor no registrado en VeriFactu"
}
}
```
---
## Headers
Every webhook delivery includes these HTTP headers:
| Header | Description |
|--------|-------------|
| `Content-Type` | `application/json` |
| `BeeL-Event` | Event type (e.g. `invoice.emitted`) |
| `BeeL-Event-Id` | Unique event ID (same as `id` in payload) |
| `BeeL-Delivery-Id` | Unique delivery attempt ID |
| `BeeL-Signature` | HMAC-SHA256 signature: `t=timestamp,v1=hash` |
| `Idempotency-Key` | Same as event ID, for idempotent processing |
---
## Environment Isolation
Webhook subscriptions are isolated per environment:
- **Production** subscriptions only receive events from production invoices (`livemode: true`)
- **Sandbox** subscriptions only receive events from sandbox invoices (`livemode: false`)
---
## Test Events
When you click **Send test event** from the dashboard, BeeL. fires a synthetic payload with the same structure but with an extra field:
```json
{
"id": "...",
"type": "verifactu.status.updated",
"livemode": false,
"test": true,
"data": {
"message": "This is a test webhook from BeeL.. Your endpoint is configured correctly."
}
}
```
Test events are not retried if your endpoint fails to respond.
---
# Overview
Receive real-time notifications in your application when events happen in BeeL.
Webhooks let your application receive HTTP notifications the moment something happens in BeeL. — no polling required. When an event occurs (e.g. AEAT processes a VeriFactu submission), BeeL. sends an HTTP `POST` to the URL you registered with a signed JSON payload.
**Developer Plan exclusive:** Webhooks are available only with the Developer Plan. See [Pricing](/pricing) for details.
## Quick Start
### 1. Create a webhook subscription
```bash
curl -X POST "https://app.beel.es/api/v1/webhooks" \
-H "Authorization: Bearer beel_sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/beel",
"events": ["invoice.emitted", "invoice.email.sent", "invoice.cancelled", "verifactu.status.updated"]
}'
```
The response contains a `secret` field — **copy it now**. It will not be shown again.
```json
{
"success": true,
"data": {
"id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"url": "https://yourapp.com/webhooks/beel",
"events": ["invoice.emitted", "invoice.email.sent", "invoice.cancelled", "verifactu.status.updated"],
"active": true,
"secret": "whsec_a3f5b2e1c9d8f7e6b5a4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2",
"created_at": "2026-03-08T10:00:00Z"
}
}
```
**Store the secret securely!** It's only shown once and required to verify webhook signatures.
### 2. Handle incoming requests
Your endpoint must:
- Accept `POST` requests with `Content-Type: application/json`
- [Verify the signature](/webhooks/signatures) using the `BeeL-Signature` header
- Return `HTTP 2xx` within **10 seconds**
```javascript
// Express.js example
app.post('/webhooks/beel', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['beel-signature'];
if (!verifySignature(req.body, signature, process.env.BEEL_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
switch (event.type) {
case 'invoice.emitted':
handleNewInvoice(event.data);
break;
case 'invoice.email.sent':
handleEmailSent(event.data);
break;
case 'invoice.cancelled':
handleCancellation(event.data);
break;
case 'verifactu.status.updated':
handleVeriFactuUpdate(event.data);
break;
}
res.status(200).send('OK');
});
```
### 3. Test your endpoint
Use the **Send test event** button in the BeeL. dashboard (Developers → Webhooks → your webhook) to fire a synthetic payload to your endpoint immediately.
**Don't have an endpoint yet?** Use [webhook.site](https://webhook.site) to get a free temporary URL that captures and displays incoming requests. It's a great way to inspect webhook payloads and verify that events are being delivered correctly before building your handler.
---
## Payload Structure
Every webhook event shares the same envelope:
```json
{
"id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"type": "verifactu.status.updated",
"created_at": "2026-03-07T16:20:26Z",
"api_version": "2025-01",
"livemode": true,
"test": null,
"data": { ... }
}
```
| Field | Type | Description |
|-------|------|-------------|
| `id` | `string` (UUID) | Unique event ID. Stays the same across all retry attempts. |
| `type` | `string` | Event type identifier (e.g. `invoice.emitted`). |
| `created_at` | `string` (ISO 8601) | When the event was generated. |
| `api_version` | `string` | API version used when the event was created (`2025-01`). |
| `livemode` | `boolean` | `false` for Sandbox API keys. |
| `test` | `boolean?` | `true` only for test deliveries triggered from the dashboard. |
| `data` | `object` | Event-specific payload. See [Events](/webhooks/events). |
---
## Limits
| Parameter | Value |
|-----------|-------|
| Max subscriptions per account | **10** |
| Max active subscriptions | **10** |
| Required URL scheme | `https://` |
| Timeout per delivery attempt | **10 seconds** |
| Max delivery attempts | **5** (1 original + 4 retries) |
| Delivery log history | **Last 50** per subscription |
---
## Headers Sent on Every Delivery
| Header | Description |
|--------|-------------|
| `Content-Type` | `application/json` |
| `BeeL-Signature` | HMAC-SHA256 signature — see [Signatures](/webhooks/signatures) |
| `BeeL-Event` | Event type (e.g. `invoice.emitted`) |
| `BeeL-Event-Id` | UUID identifying this logical event. **Identical across all retry attempts.** Matches the `id` field in the payload. |
| `BeeL-Delivery-Id` | UUID unique to this specific delivery attempt. Matches the delivery log `id` in the dashboard. |
| `Idempotency-Key` | Same value as `BeeL-Event-Id` — for automatic deduplication by frameworks |
---
## Using Official SDKs (Coming Soon)
Our official SDKs will include built-in webhook verification:
### Node.js
```typescript
import { WebhookVerifier } from '@beel_es/sdk';
const verifier = new WebhookVerifier(process.env.BEEL_WEBHOOK_SECRET);
app.post('/webhooks/beel', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = verifier.verify(
req.body.toString('utf8'),
req.headers['beel-signature']
);
// Event is verified and typed
if (event.type === 'verifactu.status.updated') {
console.log('Invoice:', event.data.invoice_number);
console.log('Status:', event.data.new_status);
}
res.status(200).send('OK');
} catch (error) {
res.status(400).send('Invalid signature');
}
});
```
### Java
```java
import es.beel.sdk.webhook.WebhookVerifier;
WebhookVerifier verifier = new WebhookVerifier(System.getenv("BEEL_WEBHOOK_SECRET"));
@PostMapping("/webhooks/beel")
public ResponseEntity handleWebhook(
@RequestBody String rawBody,
@RequestHeader("BeeL-Signature") String signature
) {
try {
var event = verifier.verify(rawBody, signature);
// Event is verified
return ResponseEntity.ok("OK");
} catch (WebhookVerificationException e) {
return ResponseEntity.status(400).body("Invalid signature");
}
}
```
See the [SDKs documentation](/sdks) for more details.
---
## What's Next
- [Events](/webhooks/events) — Available event types and their data payloads
- [Signatures](/webhooks/signatures) — Verify that requests come from BeeL.
- [Retries](/webhooks/retries) — How failed deliveries are retried
- [Deduplication](/webhooks/deduplication) — Safely handle duplicate deliveries
Questions? Email us at [it@beel.es](mailto:it@beel.es).
---
# Retries & Delivery Logs
How BeeL. retries failed deliveries and how to inspect the delivery history.
BeeL. automatically retries webhook deliveries that fail due to network errors or non-2xx HTTP responses. You can also inspect the delivery history and trigger manual retries from the dashboard or the API.
## Retry Policy
| Parameter | Value |
|-----------|-------|
| Max attempts | **5** (1 original + 4 automatic retries) |
| Retry strategy | **Exponential backoff** |
| Initial delay | **5 seconds** |
| Max delay | **6 hours** |
| Timeout per attempt | **10 seconds** |
### Backoff Schedule
| Attempt | Approximate delay after previous attempt |
|---------|----------------------------------------|
| 1st (original) | — |
| 2nd | ~5 seconds |
| 3rd | ~10 seconds |
| 4th | ~20 seconds |
| 5th | ~40 seconds |
If all 5 attempts fail, no further automatic retries occur. You can still trigger a **manual retry** from the dashboard or API at any time.
## What Triggers a Retry
| Scenario | Retried? |
|----------|----------|
| Your server returns `5xx` | ✅ Yes |
| Connection refused / DNS failure / timeout | ✅ Yes |
| Your server returns `4xx` | ❌ No — treated as a client error |
| Your server returns `2xx` | ❌ No — delivery successful |
If your endpoint returns `4xx`, BeeL. assumes the payload is invalid and will not retry. Return `5xx` if you need BeeL. to retry (e.g. your database is temporarily unavailable).
## Delivery Logs
BeeL. keeps a log of the last **50 delivery attempts** per subscription. Each log entry records:
- Delivery timestamp and duration
- HTTP status code and response body
- All request headers sent (including `BeeL-Signature`, `BeeL-Event-Id`, `BeeL-Delivery-Id`, `BeeL-Event`)
- The full JSON payload that was sent
- The attempt number
- Error description (for failed deliveries)
### View delivery logs
```bash
curl "https://app.beel.es/api/v1/webhooks/{webhook_id}/deliveries" \
-H "Authorization: Bearer beel_sk_live_xxx"
```
```json
{
"success": true,
"data": [
{
"id": "8ee6b023-c4e5-482e-93ca-dc66da2f9cb5",
"subscription_id": "3f7a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"event_type": "verifactu.status.updated",
"attempt_number": 1,
"http_status": 200,
"success": true,
"duration_ms": 142,
"response_body": "OK",
"error_message": null,
"request_headers": {
"BeeL-Signature": "t=1741362026,v1=3c4f7a2e...",
"BeeL-Event": "verifactu.status.updated",
"BeeL-Event-Id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"BeeL-Delivery-Id": "8ee6b023-c4e5-482e-93ca-dc66da2f9cb5",
"Idempotency-Key": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
},
"payload": "{\"id\":\"a1b2c3d4...\",\"type\":\"verifactu.status.updated\",...}",
"delivered_at": "2026-03-07T16:20:26Z"
}
]
}
```
### Log fields
| Field | Description |
|-------|-------------|
| `id` | Unique ID for this delivery attempt. Matches the `BeeL-Delivery-Id` header. |
| `attempt_number` | `1` for the original delivery, `2` for the first retry, etc. |
| `http_status` | HTTP status returned by your endpoint. `null` if connection failed. |
| `success` | `true` if your endpoint returned `2xx` |
| `duration_ms` | Round-trip time in milliseconds |
| `error_message` | Error detail for failed attempts (timeout, DNS error, etc.) |
| `request_headers` | Headers sent with this attempt — useful for re-verifying the signature |
| `payload` | The exact JSON body that was sent to your endpoint |
## Manual Retry
Trigger a retry for any delivery — successful or not:
```bash
curl -X POST \
"https://app.beel.es/api/v1/webhooks/{webhook_id}/deliveries/{delivery_id}/retry" \
-H "Authorization: Bearer beel_sk_live_xxx"
```
This uses the **original payload** and generates a new signature with a fresh timestamp. A new delivery log entry is created with the result.
## Endpoint Requirements
To ensure reliable delivery, your endpoint should:
- **Respond within 10 seconds** — BeeL. does not wait longer
- **Return `2xx` immediately** and process the event asynchronously if needed
- **Return `5xx`** if you are temporarily unable to process (triggers a retry)
- **Not return `4xx`** unless the payload itself is the problem
```javascript
// ✅ Good: acknowledge immediately, process async
app.post('/webhooks/beel', async (req, res) => {
res.status(200).send('OK'); // respond first
await queue.push(req.body); // process later
});
// ❌ Bad: synchronous processing blocks the response
app.post('/webhooks/beel', async (req, res) => {
await processEventSynchronously(req.body); // may exceed 10s timeout
res.status(200).send('OK');
});
```
---
# Signature Verification
Verify that webhook requests genuinely come from BeeL. using HMAC-SHA256.
Every webhook delivery includes a `BeeL-Signature` header that lets you verify the request genuinely came from BeeL. and was not tampered with. **Always verify signatures in production.**
**Using an official SDK?** The [Node.js](/sdks/node#webhooks), [Java](/sdks/java#webhooks), and [Python](/sdks/python#webhooks) SDKs include built-in `WebhookVerifier` utilities that handle all the verification logic for you. Skip to the SDK documentation for ready-to-use code.
## The `BeeL-Signature` Header
```
BeeL-Signature: t=1741362026,v1=3c4f7a2e1b9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f
```
| Component | Description |
|-----------|-------------|
| `t` | Unix timestamp (seconds) when the signature was generated |
| `v1` | HMAC-SHA256 hex digest of the signed payload |
## How to Verify
### Step-by-step
1. **Extract** `t` and `v1` from the header by splitting on `,` and then `=`
2. **Build the signed string**: concatenate `t`, a literal `.`, and the raw request body
```
signed_string = t + "." + raw_body
```
3. **Compute** `HMAC-SHA256(signed_string, secret)` where `secret` is the webhook secret you received on creation
4. **Compare** your computed digest with `v1` using a **constant-time comparison** (to prevent timing attacks)
5. **Check the timestamp**: reject if `|current_time - t| > 300` seconds (5-minute replay window)
Always read the **raw request body** (bytes) before parsing JSON. If you parse first and re-serialize, whitespace differences will break the signature.
---
## Code Examples
### Node.js
```javascript
import crypto from 'crypto';
function verifyBeelSignature(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(',').map(part => part.split('=', 2))
);
const timestamp = parts['t'];
const v1 = parts['v1'];
if (!timestamp || !v1) return false;
// Replay protection: reject requests older than 5 minutes
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp, 10)) > 300) return false;
const signedString = `${timestamp}.${rawBody}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signedString, 'utf8')
.digest('hex');
// Constant-time comparison
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(v1, 'hex')
);
}
// Express.js usage — read raw body BEFORE parsing
app.post('/webhooks/beel', express.raw({ type: 'application/json' }), (req, res) => {
const isValid = verifyBeelSignature(
req.body, // Buffer (raw bytes)
req.headers['beel-signature'],
process.env.BEEL_WEBHOOK_SECRET
);
if (!isValid) return res.status(401).send('Unauthorized');
const event = JSON.parse(req.body.toString());
// handle event...
res.status(200).send('OK');
});
```
### Python
```python
import hashlib
import hmac
import time
def verify_beel_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
parts = dict(part.split("=", 1) for part in signature_header.split(","))
timestamp = parts.get("t")
v1 = parts.get("v1")
if not timestamp or not v1:
return False
# Replay protection
if abs(time.time() - int(timestamp)) > 300:
return False
signed_string = f"{timestamp}.{raw_body.decode('utf-8')}"
expected = hmac.new(
secret.encode("utf-8"),
signed_string.encode("utf-8"),
hashlib.sha256
).hexdigest()
# Constant-time comparison
return hmac.compare_digest(expected, v1)
# FastAPI / Starlette usage
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
@app.post("/webhooks/beel")
async def webhook(request: Request):
raw_body = await request.body()
signature = request.headers.get("BeeL-Signature", "")
if not verify_beel_signature(raw_body, signature, BEEL_WEBHOOK_SECRET):
raise HTTPException(status_code=401, detail="Invalid signature")
event = await request.json()
# handle event...
return {"ok": True}
```
### PHP
```php
function verifyBeelSignature(string $rawBody, string $signatureHeader, string $secret): bool {
$parts = [];
foreach (explode(',', $signatureHeader) as $part) {
[$key, $value] = explode('=', $part, 2);
$parts[$key] = $value;
}
$timestamp = $parts['t'] ?? null;
$v1 = $parts['v1'] ?? null;
if (!$timestamp || !$v1) return false;
// Replay protection
if (abs(time() - (int)$timestamp) > 300) return false;
$signedString = "{$timestamp}.{$rawBody}";
$expected = hash_hmac('sha256', $signedString, $secret);
return hash_equals($expected, $v1);
}
$rawBody = file_get_contents('php://input');
$signatureHeader = $_SERVER['HTTP_BEEL_SIGNATURE'] ?? '';
if (!verifyBeelSignature($rawBody, $signatureHeader, getenv('BEEL_WEBHOOK_SECRET'))) {
http_response_code(401);
exit('Unauthorized');
}
$event = json_decode($rawBody, true);
// handle event...
http_response_code(200);
```
---
## Rotating the Secret
If your secret is ever compromised, rotate it immediately:
```bash
curl -X POST "https://app.beel.es/api/v1/webhooks/{webhook_id}/secret" \
-H "Authorization: Bearer beel_sk_live_xxx"
```
The old secret is **immediately invalidated** when you rotate. Update your verification logic before rotating to avoid a gap in coverage. The new secret is only returned once in this response — store it securely.
---
## Security Checklist
- [ ] Verify the signature on every incoming request
- [ ] Use constant-time comparison (avoid string `==` / `===`)
- [ ] Reject requests where `|now - t| > 300s`
- [ ] Read the **raw body bytes** — do not re-serialize before computing the HMAC
- [ ] Store the webhook secret in an environment variable, never in code
- [ ] Rotate the secret immediately if it is ever exposed
---
# Cancel representation API Reference
Cancels the current representation process.
## DELETE /v1/companies/{company_id}/representation/cancel
**Cancel representation**
Cancels the current representation process.
### Responses
#### 200: Representation cancelled
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **status** `string`: No description
- **message** `string`: No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Create a company (sub-account) API Reference
Creates a new NIF/company under the authenticated account.
Invoice series are created automatically with default values.
## POST /v1/companies
**Create a company (sub-account)**
Creates a new NIF/company under the authenticated account.
Invoice series are created automatically with default values.
### Request Body
- **nif** (required) `string`: NIF/CIF of the business
- **legal_name** (required) `string`: Legal/fiscal name
- **entity_type** (required) `string`: Type of entity - one of: INDIVIDUAL, LEGAL_ENTITY
- **address_street** (required) `string`: No description
- **address_number** `string`: No description
- **address_postal_code** (required) `string`: No description
- **address_city** (required) `string`: No description
- **address_province** (required) `string`: No description
- **address_country** `string`: No description
- **legal_form** `string`: Required for LEGAL_ENTITY
- **representative_name** `string`: Required for LEGAL_ENTITY
- **representative_nif** `string`: Required for LEGAL_ENTITY
- **business_display_name** `string`: Optional display name
- **tax_type** `string`: No description
- **tax_percentage** `number`: No description
- **irpf_percentage** `number`: No description
### Responses
#### 201: Company created
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **id** `string` (uuid): No description
- **nif** `string`: No description
- **legal_name** `string`: No description
- **business_display_name** `string`: No description
- **entity_type** `string`: No description - one of: INDIVIDUAL, LEGAL_ENTITY
- **is_primary** `boolean`: No description
- **verifactu_status** `string`: No description - one of: NOT_CONFIGURED, PENDING, ACTIVE, ERROR
- **can_issue_production_invoices** `boolean`: No description
- **created_at** `string` (date-time): No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 409: Resource conflict (e.g. duplicate)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Unprocessable entity - validation or business rule error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Create API key scoped to a company API Reference
Creates an API key that authenticates directly as this company.
The created key cannot have more scopes than the parent key.
## POST /v1/companies/{company_id}/api-keys
**Create API key scoped to a company**
Creates an API key that authenticates directly as this company.
The created key cannot have more scopes than the parent key.
### Request Body
- **name** (required) `string`: Descriptive name for the API key
- **permissions** `array[string]`: Scopes for the key (cannot exceed parent key scopes)
- **expires_in_days** `integer`: Expiration in days (optional)
### Responses
#### 201: API key created
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **key** `string`: Plain text key (only shown once)
- **prefix** `string`: No description
- **environment** `string`: No description
- **permissions** `array[string]`:
- **expires_at** `string` (date-time): No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Delete a company API Reference
Deletes a company (sub-account). Cannot delete the primary profile.
## DELETE /v1/companies/{company_id}
**Delete a company**
Deletes a company (sub-account). Cannot delete the primary profile.
### Responses
#### 204: Company deleted
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Download representation PDF API Reference
Returns a presigned URL (5min) to download the representation PDF.
## GET /v1/companies/{company_id}/representation/download
**Download representation PDF**
Returns a presigned URL (5min) to download the representation PDF.
### Responses
#### 200: Presigned download URL
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **download_url** `string` (uri): No description
- **expires_in_seconds** `integer`: No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Generate unsigned representation PDF API Reference
Generates the VeriFactu representation PDF for digital signature.
## POST /v1/companies/{company_id}/representation/generate
**Generate unsigned representation PDF**
Generates the VeriFactu representation PDF for digital signature.
### Responses
#### 200: PDF generated successfully
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **status** `string`: No description
- **message** `string`: No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get company details API Reference
Returns details of a specific company including VeriFactu status.
## GET /v1/companies/{company_id}
**Get company details**
Returns details of a specific company including VeriFactu status.
### Responses
#### 200: Company details
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **id** `string` (uuid): No description
- **nif** `string`: No description
- **legal_name** `string`: No description
- **business_display_name** `string`: No description
- **entity_type** `string`: No description - one of: INDIVIDUAL, LEGAL_ENTITY
- **is_primary** `boolean`: No description
- **verifactu_status** `string`: No description - one of: NOT_CONFIGURED, PENDING, ACTIVE, ERROR
- **can_issue_production_invoices** `boolean`: No description
- **created_at** `string` (date-time): No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get representation status API Reference
Returns the current status of the VeriFactu representation process.
## GET /v1/companies/{company_id}/representation/status
**Get representation status**
Returns the current status of the VeriFactu representation process.
### Responses
#### 200: Representation status
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **status** `string`: No description - one of: NOT_STARTED, PDF_GENERATED, SUBMITTED, ACTIVE, ERROR, CANCELLED
- **message** `string`: No description
- **updated_at** `string` (date-time): No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# List all companies API Reference
Returns all companies (sub-accounts) under the authenticated account.
## GET /v1/companies
**List all companies**
Returns all companies (sub-accounts) under the authenticated account.
### Responses
#### 200: List of companies
**Response Body:**
- **success** `boolean`: No description
- **data** `array[CompanyData]`:
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## CompanyData
### Properties
- **id** `string`: No description
- **nif** `string`: No description
- **legal_name** `string`: No description
- **business_display_name** `string`: No description
- **entity_type** `string`: No description - one of: INDIVIDUAL, LEGAL_ENTITY
- **is_primary** `boolean`: No description
- **verifactu_status** `string`: No description - one of: NOT_CONFIGURED, PENDING, ACTIVE, ERROR
- **can_issue_production_invoices** `boolean`: No description
- **created_at** `string`: No description
---
# List API keys for a company API Reference
Returns all API keys associated with this company.
## GET /v1/companies/{company_id}/api-keys
**List API keys for a company**
Returns all API keys associated with this company.
### Responses
#### 200: List of API keys
**Response Body:**
- **success** `boolean`: No description
- **data** `array[CompanyApiKeyData]`:
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## CompanyApiKeyData
### Properties
- **id** `string`: No description
- **name** `string`: No description
- **prefix** `string`: No description
- **environment** `string`: No description - one of: PRODUCTION, SANDBOX
- **permissions** `array`: No description
- **created_at** `string`: No description
- **expires_at** `string`: No description
---
# Revoke an API key API Reference
Revokes (deletes) an API key associated with this company.
## DELETE /v1/companies/{company_id}/api-keys/{key_id}
**Revoke an API key**
Revokes (deletes) an API key associated with this company.
### Responses
#### 204: API key revoked
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Submit signed representation PDF API Reference
Uploads the digitally signed representation PDF.
VeriFactu will validate the signature asynchronously.
## POST /v1/companies/{company_id}/representation/submit
**Submit signed representation PDF**
Uploads the digitally signed representation PDF.
VeriFactu will validate the signature asynchronously.
### Request Body
### Responses
#### 200: PDF submitted for validation
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **status** `string`: No description
- **message** `string`: No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 413: Payload too large - file or request body exceeds the maximum allowed size
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Update company details API Reference
Updates editable fields of a company.
NIF, legal name, and entity type are immutable after creation.
## PATCH /v1/companies/{company_id}
**Update company details**
Updates editable fields of a company.
NIF, legal name, and entity type are immutable after creation.
### Request Body
- **business_display_name** `string`: Friendly display name for the company
- **address_street** `string`: No description
- **address_number** `string`: No description
- **address_postal_code** `string`: No description
- **address_city** `string`: No description
- **address_province** `string`: No description
- **address_country** `string`: No description
### Responses
#### 200: Company updated
**Response Body:**
- **success** `boolean`: No description
- **data** `object`:
- **id** `string` (uuid): No description
- **nif** `string`: No description
- **legal_name** `string`: No description
- **business_display_name** `string`: No description
- **entity_type** `string`: No description - one of: INDIVIDUAL, LEGAL_ENTITY
- **is_primary** `boolean`: No description
- **verifactu_status** `string`: No description - one of: NOT_CONFIGURED, PENDING, ACTIVE, ERROR
- **can_issue_production_invoices** `boolean`: No description
- **created_at** `string` (date-time): No description
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Unprocessable entity - validation or business rule error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Create customer API Reference
Creates a new customer
## POST /v1/customers
**Create customer**
Creates a new customer
### Request Body
- **legal_name** (required) `string`: Customer legal name (required)
- **trade_name** `string`: Customer trade name (optional)
- **nif**: Spanish Tax ID (required if id_otro is not provided)
- **alternative_id**: No description
- **address** (required): No description
- **phone**: No description
- **email** `string` (email): Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Website URL
- **billing_emails** `array[Email]`: Additional emails for invoice delivery (optional)
- **contact_person** `string`: Contact person name (optional)
- **notes** `string`: Additional notes about the customer (optional)
- **preferred_payment_method**: No description
- **general_discount** `number`: General discount percentage (optional)
### Responses
#### 201: Customer created successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): No description (example: "123e4567-e89b-12d3-a456-426614174000")
- **legal_name** (required) `string`: No description (example: "Empresa Cliente SL")
- **trade_name** `string`: No description (example: "EmpresaCliente")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters, uppercase only).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string` (email): Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Website URL
- **billing_emails** `array[Email]`: Additional emails for invoice delivery
- **contact_person** `string`: No description (example: "María García")
- **notes** `string`: No description
- **preferred_payment_method** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **general_discount** `number`: No description
- **active** `boolean`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** `string` (date-time): No description
- **alternative_id** `object`: Alternative identifier for customers without Spanish Tax ID
- **type** (required) `string`: - 02: VAT-ID (intra-community)
- 03: Passport
- 04: Country of residence ID
- 05: Residence certificate
- 06: Other document
- 07: Not registered
- one of: 02, 03, 04, 05, 06, 07
- **number** (required) `string`: No description
- **country_code** `string`: ISO 3166-1 alpha-2 country code
#### 400: Invalid JSON format — a field has a wrong type or format (e.g. invalid date, unknown enum value, malformed UUID).
The `details` object contains `field`, `invalid_value`, and optionally `expected_format` or `allowed_values`.
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **error**: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 409: Duplicate customer (same NIF)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## Email
Email address (minimum valid email is 5 chars, e.g. a@b.co)
---
# Create or validate multiple customers API Reference
Creates multiple customers in a single operation or validates data without persisting.
**Validation flow:**
1. `dry_run=true`: Full validation only (NIFs, duplicates, format) without persistence
2. `dry_run=false`: Validation + actual creation
**Validations performed:**
- Individual validation of each customer (same rules as single customer creation)
- Detection of duplicate NIFs within the batch
- Detection of duplicate NIFs against existing database
- Parallel NIF validation against AEAT registry (VeriFactu)
- Field format verification (email, phone, etc.)
**Result statuses:**
- `VALID`: Customer valid, ready to create
- `WARNING`: Customer valid but with warnings (e.g., missing email)
- `ERROR`: Customer invalid, cannot process
- `DUPLICATE`: Duplicate NIF (in batch or existing DB)
- `NIF_INVALID`: NIF not valid in AEAT registry
**Atomicity:**
- `dry_run=true`: Validation only, no persistence
- `dry_run=false`: If any customer fails, ALL customers are rejected (full atomicity)
## POST /v1/customers/bulk
**Create or validate multiple customers**
Creates multiple customers in a single operation or validates data without persisting.
**Validation flow:**
1. `dry_run=true`: Full validation only (NIFs, duplicates, format) without persistence
2. `dry_run=false`: Validation + actual creation
**Validations performed:**
- Individual validation of each customer (same rules as single customer creation)
- Detection of duplicate NIFs within the batch
- Detection of duplicate NIFs against existing database
- Parallel NIF validation against AEAT registry (VeriFactu)
- Field format verification (email, phone, etc.)
**Result statuses:**
- `VALID`: Customer valid, ready to create
- `WARNING`: Customer valid but with warnings (e.g., missing email)
- `ERROR`: Customer invalid, cannot process
- `DUPLICATE`: Duplicate NIF (in batch or existing DB)
- `NIF_INVALID`: NIF not valid in AEAT registry
**Atomicity:**
- `dry_run=true`: Validation only, no persistence
- `dry_run=false`: If any customer fails, ALL customers are rejected (full atomicity)
### Parameters
- **dry_run** (optional) in query: Operation mode:
- `true`: Validation only without persistence (recommended for frontend preview)
- `false`: Validation + actual creation (atomic operation)
### Request Body
- **customers** (required) `array[CreateCustomerRequest]`:
### Responses
#### 200: Validation completed successfully (dry_run=true).
Returns validation results without persisting data using unified format.
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`: Unified format for customer validation results.
Used for bulk validation (JSON), CSV import and Holded Excel import.
Combines the functionality of CrearClientesBulk200Response, CsvImportPreviewResult
and HoldedImportResult into a consistent structure that simplifies the frontend.
- **metadata** (required) `object`: Metadata about the validation operation.
Compatible with bulk JSON, CSV import and Holded Excel import.
- **total_customers** (required) `integer`: Total number of customers submitted (example: 10)
- **is_dry_run** (required) `boolean`: Whether it was validation (true) or import (false) (example: true)
- **processing_time_ms** (required) `integer`: Processing time in milliseconds (example: 450)
- **source_type** (required) `string`: Data source type:
- BULK_JSON: Data sent as JSON to bulk endpoint
- CSV_IMPORT: Data parsed from CSV file
- HOLDED_EXCEL: Data parsed from Holded Excel file
- one of: BULK_JSON, CSV_IMPORT, HOLDED_EXCEL (example: "CSV_IMPORT")
- **filename** `string`: File name (CSV or Excel depending on source_type) (example: "clientes_enero.csv")
- **file_size_bytes** `integer`: File size in bytes (example: 1048576)
- **total_rows** `integer`: Total file rows excluding headers (example: 250)
- **customers_validation** (required) `array[CustomerValidationItem]`: List of processed customers with their validation status
- **statistics** (required) `object`: Aggregated validation statistics.
Compatible with all source types (bulk JSON, CSV and Holded Excel).
- **total_processed** (required) `integer`: Total customers processed (example: 10)
- **valid** (required) `integer`: Completely valid customers (no warnings or errors) (example: 6)
- **with_warnings** (required) `integer`: Valid customers but with warnings (example: 2)
- **with_errors** (required) `integer`: Customers with errors (not importable) (example: 2)
- **duplicates** (required) `integer`: Customers with duplicate NIFs (example: 1)
- **invalid_nifs** (required) `integer`: Customers with NIFs not valid in AEAT (example: 1)
- **imported** (required) `integer`: Customers actually imported (only if is_dry_run=false) (example: 0)
- **success_rate** (required) `number` (float): Success rate (valid + with_warnings) / total_processed (example: 0.8)
- **importable** `integer`: Total customers that can be imported (valid + with_warnings) (example: 8)
- **not_importable** `integer`: Total customers that CANNOT be imported (with_errors + duplicates + invalid_nifs) (example: 2)
#### 201: Customers created successfully (dry_run=false).
Atomic operation: all valid customers were created successfully.
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **customers** `array[Customer]`:
- **total_created** `integer`: No description (example: 5)
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error in one or more customers
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **error** `object`:
- **code** `string`: No description (example: "BULK_VALIDATION_ERROR")
- **message** `string`: No description
- **errors** `array[object]`:
- **index** `integer`: Index of the customer with error (0-based)
- **field** `string`: No description
- **message** `string`: No description
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## CreateCustomerRequest
### Properties
- **legal_name** (required) `string`: Customer legal name (required) (max: 120)
- **trade_name** `string`: Customer trade name (optional) (max: 120)
- **nif**: Spanish Tax ID (required if id_otro is not provided)
- **alternative_id**: No description
- **address** (required): No description
- **phone**: No description
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co) (max: 255)
- **web** `string`: Website URL (max: 255)
- **billing_emails** `array`: Additional emails for invoice delivery (optional)
- **contact_person** `string`: Contact person name (optional) (max: 200)
- **notes** `string`: Additional notes about the customer (optional)
- **preferred_payment_method**: No description
- **general_discount** `number`: General discount percentage (optional) (min: 0) (max: 100)
## CustomerValidationItem
Individual customer validation result.
Works for bulk JSON, CSV import and Holded Excel import.
### Properties
- **index** (required) `integer`: Customer index in the submitted list (0-based for bulk, 1-based for files).
For CSV/Excel, represents the row number in the file.
- **customer** (required): Parsed and validated customer.
Can be null if there were critical parsing errors.
- **status** (required) `string`: Customer validation status:
- VALID: Completely valid customer
- WARNING: Valid customer but with non-critical warnings
- ERROR: Invalid customer, cannot be processed
- DUPLICATE: Duplicate customer (in batch/CSV or database)
- NIF_INVALID: NIF not valid according to AEAT census (VeriFactu)
- one of: VALID, WARNING, ERROR, DUPLICATE, NIF_INVALID
- **errors** (required) `array`: List of errors found (block import)
- **warnings** (required) `array`: List of warnings (do not block import)
- **row_number** `integer`: Row number in the file (CSV or Excel depending on source_type)
## Customer
### Properties
- **id** (required) `string`: No description
- **legal_name** (required) `string`: No description
- **trade_name** `string`: No description
- **nif**: No description
- **address** (required): No description
- **phone**: No description
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co) (max: 255)
- **web** `string`: Website URL (max: 255)
- **billing_emails** `array`: Additional emails for invoice delivery
- **contact_person** `string`: No description
- **notes** `string`: No description (max: 1000)
- **preferred_payment_method**: No description
- **general_discount** `number`: No description (default: 0) (min: 0) (max: 100)
- **active** `boolean`: No description (default: true)
- **created_at** (required) `string`: No description
- **updated_at** `string`: No description
- **alternative_id**: No description
---
# Deactivate customer API Reference
Deactivates (marks as deleted) a customer.
**Soft delete:** The customer is not physically deleted, only marked as inactive.
**Restriction:** Cannot deactivate a customer with associated invoices.
## DELETE /v1/customers/{customer_id}
**Deactivate customer**
Deactivates (marks as deleted) a customer.
**Soft delete:** The customer is not physically deleted, only marked as inactive.
**Restriction:** Cannot deactivate a customer with associated invoices.
### Parameters
- **customer_id** (required) in path: Customer ID
### Responses
#### 200: Customer deactivated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **message** (required) `string`: No description (example: "Customer deactivated successfully")
#### 400: Cannot deactivate (has associated invoices)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Delete multiple customers API Reference
Deactivates (marks as deleted) multiple customers in a single operation.
**Soft delete:** Customers are not physically deleted, only marked as inactive.
**Partial behavior:** Valid customers will be deactivated, failures are reported in the errors array.
## DELETE /v1/customers/bulk
**Delete multiple customers**
Deactivates (marks as deleted) multiple customers in a single operation.
**Soft delete:** Customers are not physically deleted, only marked as inactive.
**Partial behavior:** Valid customers will be deactivated, failures are reported in the errors array.
### Parameters
- **ids** (required) in query: Comma-separated customer IDs
### Responses
#### 200: Operation completed (may have partial errors)
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **total** (required) `integer`: Total customers processed (example: 10)
- **successful** (required) `integer`: Number of successful deactivations (example: 8)
- **failed** (required) `integer`: Number of failed deactivations (example: 2)
- **deactivated_ids** (required) `array[UUID]`: IDs of successfully deactivated customers
- **errors** `array[object]`: Details of customers that could not be deactivated
- **customer_id** (required) `string`: Universally Unique Identifier (UUID v4)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "CLIENT_HAS_INVOICES")
- **message** (required) `string`: No description (example: "Cannot deactivate customer because it has associated invoices")
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## UUID
Universally Unique Identifier (UUID v4)
---
# Download CSV template for customers API Reference
Downloads a sample CSV file for customer import.
**Format**: The file includes the required headers and example rows
with UTF-8 BOM for Excel compatibility.
## POST /v1/customers/templates/csv
**Download CSV template for customers**
Downloads a sample CSV file for customer import.
**Format**: The file includes the required headers and example rows
with UTF-8 BOM for Excel compatibility.
### Responses
#### 200: CSV template downloaded successfully
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get customer by ID API Reference
Retrieves complete details of a specific customer
## GET /v1/customers/{customer_id}
**Get customer by ID**
Retrieves complete details of a specific customer
### Parameters
- **customer_id** (required) in path: Customer ID
### Responses
#### 200: Customer retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): No description (example: "123e4567-e89b-12d3-a456-426614174000")
- **legal_name** (required) `string`: No description (example: "Empresa Cliente SL")
- **trade_name** `string`: No description (example: "EmpresaCliente")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters, uppercase only).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string` (email): Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Website URL
- **billing_emails** `array[Email]`: Additional emails for invoice delivery
- **contact_person** `string`: No description (example: "María García")
- **notes** `string`: No description
- **preferred_payment_method** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **general_discount** `number`: No description
- **active** `boolean`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** `string` (date-time): No description
- **alternative_id** `object`: Alternative identifier for customers without Spanish Tax ID
- **type** (required) `string`: - 02: VAT-ID (intra-community)
- 03: Passport
- 04: Country of residence ID
- 05: Residence certificate
- 06: Other document
- 07: Not registered
- one of: 02, 03, 04, 05, 06, 07
- **number** (required) `string`: No description
- **country_code** `string`: ISO 3166-1 alpha-2 country code
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## Email
Email address (minimum valid email is 5 chars, e.g. a@b.co)
---
# Import customers from CSV with structured preview API Reference
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
## POST /v1/customers/import-csv-preview
**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
### Request Body
### Responses
#### 200: CSV processing completed with structured preview using unified format
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`: Unified format for customer validation results.
Used for bulk validation (JSON), CSV import and Holded Excel import.
Combines the functionality of CrearClientesBulk200Response, CsvImportPreviewResult
and HoldedImportResult into a consistent structure that simplifies the frontend.
- **metadata** (required) `object`: Metadata about the validation operation.
Compatible with bulk JSON, CSV import and Holded Excel import.
- **total_customers** (required) `integer`: Total number of customers submitted (example: 10)
- **is_dry_run** (required) `boolean`: Whether it was validation (true) or import (false) (example: true)
- **processing_time_ms** (required) `integer`: Processing time in milliseconds (example: 450)
- **source_type** (required) `string`: Data source type:
- BULK_JSON: Data sent as JSON to bulk endpoint
- CSV_IMPORT: Data parsed from CSV file
- HOLDED_EXCEL: Data parsed from Holded Excel file
- one of: BULK_JSON, CSV_IMPORT, HOLDED_EXCEL (example: "CSV_IMPORT")
- **filename** `string`: File name (CSV or Excel depending on source_type) (example: "clientes_enero.csv")
- **file_size_bytes** `integer`: File size in bytes (example: 1048576)
- **total_rows** `integer`: Total file rows excluding headers (example: 250)
- **customers_validation** (required) `array[CustomerValidationItem]`: List of processed customers with their validation status
- **statistics** (required) `object`: Aggregated validation statistics.
Compatible with all source types (bulk JSON, CSV and Holded Excel).
- **total_processed** (required) `integer`: Total customers processed (example: 10)
- **valid** (required) `integer`: Completely valid customers (no warnings or errors) (example: 6)
- **with_warnings** (required) `integer`: Valid customers but with warnings (example: 2)
- **with_errors** (required) `integer`: Customers with errors (not importable) (example: 2)
- **duplicates** (required) `integer`: Customers with duplicate NIFs (example: 1)
- **invalid_nifs** (required) `integer`: Customers with NIFs not valid in AEAT (example: 1)
- **imported** (required) `integer`: Customers actually imported (only if is_dry_run=false) (example: 0)
- **success_rate** (required) `number` (float): Success rate (valid + with_warnings) / total_processed (example: 0.8)
- **importable** `integer`: Total customers that can be imported (valid + with_warnings) (example: 8)
- **not_importable** `integer`: Total customers that CANNOT be imported (with_errors + duplicates + invalid_nifs) (example: 2)
#### 400: Invalid file for one of the following reasons:
- Format is not valid CSV
- Encoding is not UTF-8
- Required headers missing
- Size exceeds 5MB
- More than 1,000 records
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **error** `object`:
- **details** `object`:
- **file_size_mb** `number`: File size in MB
- **record_count** `integer`: Number of records found
- **missing_headers** `array[string]`: Required headers that are missing
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 413: File too large (>5MB)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Structural CSV validation error (corrupted format, invalid encoding)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 429: Rate limit exceeded (maximum 3 imports per hour)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## CustomerValidationItem
Individual customer validation result.
Works for bulk JSON, CSV import and Holded Excel import.
### Properties
- **index** (required) `integer`: Customer index in the submitted list (0-based for bulk, 1-based for files).
For CSV/Excel, represents the row number in the file.
- **customer** (required): Parsed and validated customer.
Can be null if there were critical parsing errors.
- **status** (required) `string`: Customer validation status:
- VALID: Completely valid customer
- WARNING: Valid customer but with non-critical warnings
- ERROR: Invalid customer, cannot be processed
- DUPLICATE: Duplicate customer (in batch/CSV or database)
- NIF_INVALID: NIF not valid according to AEAT census (VeriFactu)
- one of: VALID, WARNING, ERROR, DUPLICATE, NIF_INVALID
- **errors** (required) `array`: List of errors found (block import)
- **warnings** (required) `array`: List of warnings (do not block import)
- **row_number** `integer`: Row number in the file (CSV or Excel depending on source_type)
---
# Import contacts from Holded Excel API Reference
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
## POST /v1/customers/import-holded-contacts
**Import contacts from Holded Excel**
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
### Request Body
### Responses
#### 200: Holded Excel processing completed with unified format.
Returns parsed, validated and mapped customers using the same format as CSV import.
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`: Unified format for customer validation results.
Used for bulk validation (JSON), CSV import and Holded Excel import.
Combines the functionality of CrearClientesBulk200Response, CsvImportPreviewResult
and HoldedImportResult into a consistent structure that simplifies the frontend.
- **metadata** (required) `object`: Metadata about the validation operation.
Compatible with bulk JSON, CSV import and Holded Excel import.
- **total_customers** (required) `integer`: Total number of customers submitted (example: 10)
- **is_dry_run** (required) `boolean`: Whether it was validation (true) or import (false) (example: true)
- **processing_time_ms** (required) `integer`: Processing time in milliseconds (example: 450)
- **source_type** (required) `string`: Data source type:
- BULK_JSON: Data sent as JSON to bulk endpoint
- CSV_IMPORT: Data parsed from CSV file
- HOLDED_EXCEL: Data parsed from Holded Excel file
- one of: BULK_JSON, CSV_IMPORT, HOLDED_EXCEL (example: "CSV_IMPORT")
- **filename** `string`: File name (CSV or Excel depending on source_type) (example: "clientes_enero.csv")
- **file_size_bytes** `integer`: File size in bytes (example: 1048576)
- **total_rows** `integer`: Total file rows excluding headers (example: 250)
- **customers_validation** (required) `array[CustomerValidationItem]`: List of processed customers with their validation status
- **statistics** (required) `object`: Aggregated validation statistics.
Compatible with all source types (bulk JSON, CSV and Holded Excel).
- **total_processed** (required) `integer`: Total customers processed (example: 10)
- **valid** (required) `integer`: Completely valid customers (no warnings or errors) (example: 6)
- **with_warnings** (required) `integer`: Valid customers but with warnings (example: 2)
- **with_errors** (required) `integer`: Customers with errors (not importable) (example: 2)
- **duplicates** (required) `integer`: Customers with duplicate NIFs (example: 1)
- **invalid_nifs** (required) `integer`: Customers with NIFs not valid in AEAT (example: 1)
- **imported** (required) `integer`: Customers actually imported (only if is_dry_run=false) (example: 0)
- **success_rate** (required) `number` (float): Success rate (valid + with_warnings) / total_processed (example: 0.8)
- **importable** `integer`: Total customers that can be imported (valid + with_warnings) (example: 8)
- **not_importable** `integer`: Total customers that CANNOT be imported (with_errors + duplicates + invalid_nifs) (example: 2)
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 413: File too large (>10MB)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 429: Rate limit exceeded (maximum 5 imports per hour)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## CustomerValidationItem
Individual customer validation result.
Works for bulk JSON, CSV import and Holded Excel import.
### Properties
- **index** (required) `integer`: Customer index in the submitted list (0-based for bulk, 1-based for files).
For CSV/Excel, represents the row number in the file.
- **customer** (required): Parsed and validated customer.
Can be null if there were critical parsing errors.
- **status** (required) `string`: Customer validation status:
- VALID: Completely valid customer
- WARNING: Valid customer but with non-critical warnings
- ERROR: Invalid customer, cannot be processed
- DUPLICATE: Duplicate customer (in batch/CSV or database)
- NIF_INVALID: NIF not valid according to AEAT census (VeriFactu)
- one of: VALID, WARNING, ERROR, DUPLICATE, NIF_INVALID
- **errors** (required) `array`: List of errors found (block import)
- **warnings** (required) `array`: List of warnings (do not block import)
- **row_number** `integer`: Row number in the file (CSV or Excel depending on source_type)
---
# List customers API Reference
Returns a paginated list of customers with optional filters
## GET /v1/customers
**List customers**
Returns a paginated list of customers with optional filters
### Parameters
- **undefined** (optional): No description
- **undefined** (optional): No description
- **active** (optional) in query: Filter by active/inactive status
- **search** (optional) in query: Global search by name, NIF or email
- **legal_name** (optional) in query: Filter by legal name (partial search case-insensitive)
- **nif** (optional) in query: Filter by NIF (partial search)
- **email** (optional) in query: Filter by email (partial search)
- **phone** (optional) in query: Filter by phone (partial search)
- **city** (optional) in query: Filter by city
- **province** (optional) in query: Filter by province
- **sort_by** (optional) in query: Field to sort by (eg. legal_name, nif, created_at)
- **sort_order** (optional) in query: Sort order direction
### Responses
#### 200: Customer list retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **customers** (required) `array[Customer]`:
- **pagination** (required) `object`:
- **current_page** (required) `integer`: No description (example: 1)
- **total_pages** (required) `integer`: No description (example: 5)
- **total_items** (required) `integer`: No description (example: 87)
- **items_per_page** (required) `integer`: No description (example: 20)
- **has_next** `boolean`: No description
- **has_previous** `boolean`: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## Customer
### Properties
- **id** (required) `string`: No description
- **legal_name** (required) `string`: No description
- **trade_name** `string`: No description
- **nif**: No description
- **address** (required): No description
- **phone**: No description
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co) (max: 255)
- **web** `string`: Website URL (max: 255)
- **billing_emails** `array`: Additional emails for invoice delivery
- **contact_person** `string`: No description
- **notes** `string`: No description (max: 1000)
- **preferred_payment_method**: No description
- **general_discount** `number`: No description (default: 0) (min: 0) (max: 100)
- **active** `boolean`: No description (default: true)
- **created_at** (required) `string`: No description
- **updated_at** `string`: No description
- **alternative_id**: No description
---
# Update customer API Reference
Updates an existing customer
## PUT /v1/customers/{customer_id}
**Update customer**
Updates an existing customer
### Parameters
- **customer_id** (required) in path: Customer ID
### Request Body
- **legal_name** `string`: Customer legal name
- **trade_name** `string`: Customer trade name (optional)
- **address**: No description
- **phone**: No description
- **email** `string` (email): Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Website URL
- **billing_emails** `array[Email]`: Additional emails for invoice delivery (optional)
- **contact_person** `string`: Contact person name (optional)
- **notes** `string`: Additional notes about the customer (optional)
- **preferred_payment_method**: No description
- **general_discount** `number`: General discount percentage (optional)
- **active** `boolean`: Whether the customer is active or inactive
### Responses
#### 200: Customer updated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): No description (example: "123e4567-e89b-12d3-a456-426614174000")
- **legal_name** (required) `string`: No description (example: "Empresa Cliente SL")
- **trade_name** `string`: No description (example: "EmpresaCliente")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters, uppercase only).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string` (email): Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Website URL
- **billing_emails** `array[Email]`: Additional emails for invoice delivery
- **contact_person** `string`: No description (example: "María García")
- **notes** `string`: No description
- **preferred_payment_method** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **general_discount** `number`: No description
- **active** `boolean`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** `string` (date-time): No description
- **alternative_id** `object`: Alternative identifier for customers without Spanish Tax ID
- **type** (required) `string`: - 02: VAT-ID (intra-community)
- 03: Passport
- 04: Country of residence ID
- 05: Residence certificate
- 06: Other document
- 07: Not registered
- one of: 02, 03, 04, 05, 06, 07
- **number** (required) `string`: No description
- **country_code** `string`: ISO 3166-1 alpha-2 country code
#### 400: Invalid JSON format — a field has a wrong type or format (e.g. invalid date, unknown enum value, malformed UUID).
The `details` object contains `field`, `invalid_value`, and optionally `expected_format` or `allowed_values`.
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **error**: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## Email
Email address (minimum valid email is 5 chars, e.g. a@b.co)
---
# Create invoice series API Reference
Creates a new invoice series.
**Note:** The first series created by a user is automatically marked as default.
## POST /v1/configuration/series
**Create invoice series**
Creates a new invoice series.
**Note:** The first series created by a user is automatically marked as default.
### Request Body
- **name** (required) `string`: Descriptive name of the series
- **code** (required): No description
- **description** `string`: Optional series description
- **format** (required): No description
- **counter_reset** (required): No description
- **initial_number** `integer` (int64): Initial number for this series counter.
Useful when migrating from another system and wanting to continue existing numbering.
For example, if the last invoices were 2024-0150, you can set initial_number=151.
Default value is 1.
- **active** `boolean`: Whether the series is active
- **default_series** `boolean`: Whether this is the default series
### Responses
#### 201: Series created successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique series ID
- **name** (required) `string`: Descriptive name of the series (example: "Main Series")
- **code** (required) `string`: Alphanumeric series code (used in {CODIGO} variable).
Allows uppercase letters, numbers, hyphens and underscores.
- **description** `string`: Optional series description (example: "Series for standard invoices")
- **format** (required) `string`: Format template with available variables (UPPERCASE ONLY):
- {CODIGO}: Series code (e.g., "FAC")
- {YYYY}: Year with 4 digits (e.g., "2025")
- {YY}: Year with 2 digits (e.g., "25")
- {MM}: Month with 2 digits (e.g., "01")
- {NUM}: Sequential number without padding (e.g., "1")
- {NUM:X}: Sequential number with padding (e.g., {NUM:4} → "0001")
**REQUIRED**: Must contain at least {NUM} or {NUM:X}
**IMPORTANT**: Only uppercase (rejects {yy}, {mm}, {codigo}, etc.)
Valid examples:
- "{CODIGO}-{YYYY}-{NUM:4}" → "FAC-2025-0001"
- "{CODIGO}/{NUM:6}" → "FAC/000001"
- "{YYYY}{MM}-{NUM:3}" → "202501-001"
- **counter_reset** (required) `string`: Counter reset policy:
- NEVER: Counter never resets (continuous numbering)
- ANNUAL: Counter resets yearly
- MONTHLY: Counter resets monthly
- **initial_number** `integer` (int64): Initial number configured for this series counter.
Defines from which number invoice numbering will start.
(example: 1)
- **active** (required) `boolean`: Indicates whether the series is active
- **default_series** (required) `boolean`: Indicates whether this is the user's default series (only one can be)
- **created_at** `string` (date-time): Creation date
- **next_number** `integer` (int64): Next invoice number that will be assigned for this series
- **updated_at** `string` (date-time): Last update date
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 409: Duplicate series (same code)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Delete series API Reference
Soft-deletes an invoice series. If the series is active, it is automatically
deactivated before deletion. The series code becomes available for reuse.
**Restriction:** Cannot delete the default series. Assign another series as default first.
## DELETE /v1/configuration/series/{series_id}
**Delete series**
Soft-deletes an invoice series. If the series is active, it is automatically
deactivated before deletion. The series code becomes available for reuse.
**Restriction:** Cannot delete the default series. Assign another series as default first.
### Parameters
- **series_id** (required) in path: Series ID
### Responses
#### 204: Series deleted successfully
#### 400: Cannot delete the default series
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# List invoice series API Reference
Retrieves all invoice series for the user
## GET /v1/configuration/series
**List invoice series**
Retrieves all invoice series for the user
### Parameters
- **active** (optional) in query: Filter by active/inactive series
### Responses
#### 200: Series retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `array[InvoiceSeries]`:
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceSeries
### Properties
- **id** (required) `string`: Unique series ID
- **name** (required) `string`: Descriptive name of the series (max: 100)
- **code** (required): No description
- **description** `string`: Optional series description (max: 1000)
- **format** (required): No description
- **counter_reset** (required): No description
- **initial_number** `integer`: Initial number configured for this series counter.
Defines from which number invoice numbering will start.
(default: 1) (min: 1) (max: 999999)
- **active** (required) `boolean`: Indicates whether the series is active (default: true)
- **default_series** (required) `boolean`: Indicates whether this is the user's default series (only one can be) (default: false)
- **created_at** `string`: Creation date
- **next_number** `integer`: Next invoice number that will be assigned for this series
- **updated_at** `string`: Last update date
---
# Mark series as default API Reference
Marks an invoice series as the user's default.
**Business rules:**
- Only one series can be default per user
- The series must be active (cannot mark an inactive series)
- The previous default series is automatically unmarked
**Note:** This operation is idempotent - calling it multiple times
with the same series has no additional effects.
## POST /v1/configuration/series/{series_id}/default
**Mark series as default**
Marks an invoice series as the user's default.
**Business rules:**
- Only one series can be default per user
- The series must be active (cannot mark an inactive series)
- The previous default series is automatically unmarked
**Note:** This operation is idempotent - calling it multiple times
with the same series has no additional effects.
### Parameters
- **series_id** (required) in path: Series ID to mark as default
### Responses
#### 200: Series marked as default successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique series ID
- **name** (required) `string`: Descriptive name of the series (example: "Main Series")
- **code** (required) `string`: Alphanumeric series code (used in {CODIGO} variable).
Allows uppercase letters, numbers, hyphens and underscores.
- **description** `string`: Optional series description (example: "Series for standard invoices")
- **format** (required) `string`: Format template with available variables (UPPERCASE ONLY):
- {CODIGO}: Series code (e.g., "FAC")
- {YYYY}: Year with 4 digits (e.g., "2025")
- {YY}: Year with 2 digits (e.g., "25")
- {MM}: Month with 2 digits (e.g., "01")
- {NUM}: Sequential number without padding (e.g., "1")
- {NUM:X}: Sequential number with padding (e.g., {NUM:4} → "0001")
**REQUIRED**: Must contain at least {NUM} or {NUM:X}
**IMPORTANT**: Only uppercase (rejects {yy}, {mm}, {codigo}, etc.)
Valid examples:
- "{CODIGO}-{YYYY}-{NUM:4}" → "FAC-2025-0001"
- "{CODIGO}/{NUM:6}" → "FAC/000001"
- "{YYYY}{MM}-{NUM:3}" → "202501-001"
- **counter_reset** (required) `string`: Counter reset policy:
- NEVER: Counter never resets (continuous numbering)
- ANNUAL: Counter resets yearly
- MONTHLY: Counter resets monthly
- **initial_number** `integer` (int64): Initial number configured for this series counter.
Defines from which number invoice numbering will start.
(example: 1)
- **active** (required) `boolean`: Indicates whether the series is active
- **default_series** (required) `boolean`: Indicates whether this is the user's default series (only one can be)
- **created_at** `string` (date-time): Creation date
- **next_number** `integer` (int64): Next invoice number that will be assigned for this series
- **updated_at** `string` (date-time): Last update date
#### 400: Cannot mark as default (inactive series)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Update invoice series API Reference
Updates an existing invoice series.
Can only update:
- Description
- Active/inactive status
- Whether it is default
Cannot modify: code, prefix, number_format (to maintain consistency with existing invoices).
Business rules:
- Cannot deactivate a default series (must set another as default first)
- Cannot mark an inactive series as default
## PUT /v1/configuration/series/{series_id}
**Update invoice series**
Updates an existing invoice series.
Can only update:
- Description
- Active/inactive status
- Whether it is default
Cannot modify: code, prefix, number_format (to maintain consistency with existing invoices).
Business rules:
- Cannot deactivate a default series (must set another as default first)
- Cannot mark an inactive series as default
### Parameters
- **series_id** (required) in path: Series ID
### Request Body
- **name** `string`: Descriptive name of the series
- **code**: No description
- **description** `string`: Optional series description
- **format**: No description
- **counter_reset**: No description
- **initial_number** `integer` (int64): Initial number for this series counter.
Useful for adjusting numbering or resetting the counter.
For example, if you want the next invoice to be 2025-0054, set initial_number=54.
- **active** `boolean`: Whether the series is active.
**Restriction:** A default series cannot be deactivated
(another must be set as default first).
- **default_series** `boolean`: Whether this is the default series.
**Restriction:** An inactive series cannot be marked as default.
### Responses
#### 200: Series updated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique series ID
- **name** (required) `string`: Descriptive name of the series (example: "Main Series")
- **code** (required) `string`: Alphanumeric series code (used in {CODIGO} variable).
Allows uppercase letters, numbers, hyphens and underscores.
- **description** `string`: Optional series description (example: "Series for standard invoices")
- **format** (required) `string`: Format template with available variables (UPPERCASE ONLY):
- {CODIGO}: Series code (e.g., "FAC")
- {YYYY}: Year with 4 digits (e.g., "2025")
- {YY}: Year with 2 digits (e.g., "25")
- {MM}: Month with 2 digits (e.g., "01")
- {NUM}: Sequential number without padding (e.g., "1")
- {NUM:X}: Sequential number with padding (e.g., {NUM:4} → "0001")
**REQUIRED**: Must contain at least {NUM} or {NUM:X}
**IMPORTANT**: Only uppercase (rejects {yy}, {mm}, {codigo}, etc.)
Valid examples:
- "{CODIGO}-{YYYY}-{NUM:4}" → "FAC-2025-0001"
- "{CODIGO}/{NUM:6}" → "FAC/000001"
- "{YYYY}{MM}-{NUM:3}" → "202501-001"
- **counter_reset** (required) `string`: Counter reset policy:
- NEVER: Counter never resets (continuous numbering)
- ANNUAL: Counter resets yearly
- MONTHLY: Counter resets monthly
- **initial_number** `integer` (int64): Initial number configured for this series counter.
Defines from which number invoice numbering will start.
(example: 1)
- **active** (required) `boolean`: Indicates whether the series is active
- **default_series** (required) `boolean`: Indicates whether this is the user's default series (only one can be)
- **created_at** `string` (date-time): Creation date
- **next_number** `integer` (int64): Next invoice number that will be assigned for this series
- **updated_at** `string` (date-time): Last update date
#### 400: Cannot update (has associated invoices)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Change status of multiple invoices API Reference
Changes the status of multiple invoices in a single operation.
**Supported status changes:**
- **SENT:** Mark multiple invoices as sent (from ISSUED)
- **PAID:** Mark multiple invoices as paid (from ISSUED, SENT, or OVERDUE)
**Partial success:** If some invoices cannot be updated, the operation
continues with the others. The response includes details of failures.
**Limits:**
- Maximum 50 invoices per request
**Validations:**
- All invoices must belong to the authenticated user
- Each invoice must be in a valid status for the requested transition
- For PAID: payment_date is required
## POST /v1/invoices/bulk/status
**Change status of multiple invoices**
Changes the status of multiple invoices in a single operation.
**Supported status changes:**
- **SENT:** Mark multiple invoices as sent (from ISSUED)
- **PAID:** Mark multiple invoices as paid (from ISSUED, SENT, or OVERDUE)
**Partial success:** If some invoices cannot be updated, the operation
continues with the others. The response includes details of failures.
**Limits:**
- Maximum 50 invoices per request
**Validations:**
- All invoices must belong to the authenticated user
- Each invoice must be in a valid status for the requested transition
- For PAID: payment_date is required
### Request Body
- **invoice_ids** (required) `array[UUID]`: List of invoice IDs to update
- **new_status** (required) `string`: Target status for the invoices - one of: SENT, PAID
- **payment_date** `string` (date): Payment date (required when new_status is PAID)
### Responses
#### 200: Status change operation completed (may include partial failures)
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **total** (required) `integer`: Total number of invoices processed (example: 5)
- **successful** (required) `integer`: Number of invoices successfully updated (example: 4)
- **failed** (required) `integer`: Number of invoices that failed to update (example: 1)
- **failures** `array[object]`: Details of failed updates
- **invoice_id** (required) `string`: Universally Unique Identifier (UUID v4)
- **reason** (required) `string`: Reason for the failure (example: "Cannot change from PAID to SENT")
#### 400: Invalid request (empty list, missing payment_date for PAID)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error (unsupported status, too many invoices)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## UUID
Universally Unique Identifier (UUID v4)
---
# Create corrective invoice API Reference
Creates a corrective invoice to correct or void an issued invoice.
**Rectification types:**
- **TOTAL**: Completely voids the original invoice (original status → VOIDED)
- **PARTIAL**: Partially corrects the original invoice (original status → RECTIFIED)
**VeriFactu codes:**
- R1: Legal error and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy)
- R3: Article 80 Four LIVA (Bad debts)
- R4: Other causes
- R5: Simplified invoices (only for simplified)
**Validations:**
- Original invoice must be in status ISSUED, SENT, PAID, OVERDUE or RECTIFIED
- Cannot rectify a DRAFT invoice (must be issued first)
- Cannot rectify a VOIDED invoice (final status)
- For TOTAL rectification: Another total corrective cannot already exist
- For PARTIAL rectification: Multiple partial correctives are allowed
**Lines:**
- TOTAL: Optional (if not provided, original lines are copied with negated amounts)
- PARTIAL: REQUIRED (adjustment lines with positive or negative amounts)
## POST /v1/invoices/{invoice_id}/corrective
**Create corrective invoice**
Creates a corrective invoice to correct or void an issued invoice.
**Rectification types:**
- **TOTAL**: Completely voids the original invoice (original status → VOIDED)
- **PARTIAL**: Partially corrects the original invoice (original status → RECTIFIED)
**VeriFactu codes:**
- R1: Legal error and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy)
- R3: Article 80 Four LIVA (Bad debts)
- R4: Other causes
- R5: Simplified invoices (only for simplified)
**Validations:**
- Original invoice must be in status ISSUED, SENT, PAID, OVERDUE or RECTIFIED
- Cannot rectify a DRAFT invoice (must be issued first)
- Cannot rectify a VOIDED invoice (final status)
- For TOTAL rectification: Another total corrective cannot already exist
- For PARTIAL rectification: Multiple partial correctives are allowed
**Lines:**
- TOTAL: Optional (if not provided, original lines are copied with negated amounts)
- PARTIAL: REQUIRED (adjustment lines with positive or negative amounts)
### Parameters
- **invoice_id** (required) in path: Invoice ID to rectify
- **undefined** (optional): No description
### Request Body
- **rectification_type** (required): No description
- **rectification_code** (required): No description
- **reason** (required) `string`: Detailed reason for rectification (minimum 10 characters)
- **lines** `array[object]`: **TOTAL**: Optional (if not sent, original invoice lines are copied negated)
**PARTIAL**: REQUIRED (adjustment lines with positive or negative amounts)
- **description** (required) `string`: Concept description
- **quantity** (required) `number`: Quantity (can be negative for corrective invoices)
- **unit** `string`: No description
- **unit_price** (required) `number`: Unit price before taxes (can be negative in corrective invoices).
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
- **discount_percentage** `number`: No description
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **notes** `string`: Additional observations about the rectification
- **series_id** `string` (uuid): Series for the corrective invoice (optional, if not specified uses the original invoice's series)
- **options**: No description
### Responses
#### 201: Corrective invoice created successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Invalid rectification data
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Original invoice not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 409: A total corrective invoice already exists for this invoice
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Original invoice cannot be rectified (invalid status)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Create invoice API Reference
Creates a new invoice.
**Idempotency:** Supports `Idempotency-Key` header to prevent duplicates.
## POST /v1/invoices
**Create invoice**
Creates a new invoice.
**Idempotency:** Supports `Idempotency-Key` header to prevent duplicates.
### Parameters
- **Idempotency-Key** (optional) in header: UUID to prevent duplicates (recommended)
### Request Body
- **type** (required): No description
- **series_id** `string` (uuid): Invoicing series ID (if not specified, uses default)
- **issue_date** (required) `string` (date): No description
- **due_date** `string` (date): If not specified, calculated according to payment method. If provided, it must be the same as or after `issue_date`.
- **recipient** (required): No description
- **lines** (required) `array[object]`:
- **description** (required) `string`: Description of invoiced concept
- **quantity** (required) `number`: Product/service quantity (can be negative for franchises or discounts)
- **unit** `string`: No description
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
- **discount_percentage** `number`: Discount percentage applied (0-100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **payment_info**: No description
- **notes** `string`: No description
- **rectified_invoice_id** `string` (uuid): Required if type is "CORRECTIVE"
- **rectification_reason** `string`: Required if type is "CORRECTIVE"
- **metadata** `object`: Additional metadata in key-value format. Useful for storing references
to external systems like Stripe, order IDs, etc.
- **options**: No description
### Responses
#### 201: Invoice created successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Invalid JSON format — a field has a wrong type or format (e.g. invalid date, unknown enum value, malformed UUID).
The `details` object contains `field`, `invalid_value`, and optionally `expected_format` or `allowed_values`.
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **error**: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 409: Conflict - Idempotency key already processed or duplicate invoice number
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Delete invoice API Reference
Deletes (marks as deleted) an invoice.
**Soft delete:** The invoice is not physically deleted, only marked as deleted.
**Restriction:** Only invoices in `DRAFT` status can be deleted.
## DELETE /v1/invoices/{invoice_id}
**Delete invoice**
Deletes (marks as deleted) an invoice.
**Soft delete:** The invoice is not physically deleted, only marked as deleted.
**Restriction:** Only invoices in `DRAFT` status can be deleted.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Responses
#### 204: Invoice deleted successfully
#### 400: Cannot delete (invoice already sent/paid)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Download multiple invoice PDFs as ZIP API Reference
Downloads multiple invoice PDFs as a single ZIP file.
**Limits:**
- Maximum 20 invoices per request
- Maximum 50MB total ZIP size
**Partial success:** If some PDFs are not available (not generated, not found),
the response will include a `failures` array with details. The ZIP will still
be generated with the available PDFs.
**Error handling:**
- If NO PDFs are available, returns 400 Bad Request
- If some PDFs are unavailable, returns 200 with partial ZIP + failures list
## POST /v1/invoices/bulk/pdf
**Download multiple invoice PDFs as ZIP**
Downloads multiple invoice PDFs as a single ZIP file.
**Limits:**
- Maximum 20 invoices per request
- Maximum 50MB total ZIP size
**Partial success:** If some PDFs are not available (not generated, not found),
the response will include a `failures` array with details. The ZIP will still
be generated with the available PDFs.
**Error handling:**
- If NO PDFs are available, returns 400 Bad Request
- If some PDFs are unavailable, returns 200 with partial ZIP + failures list
### Request Body
- **invoice_ids** (required) `array[UUID]`: List of invoice IDs to download
### Responses
#### 200: ZIP file with invoice PDFs
#### 400: No valid PDFs available or invalid request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error (too many invoices, empty list)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## UUID
Universally Unique Identifier (UUID v4)
---
# Duplicate invoice as draft API Reference
Creates a copy of an existing invoice as a new draft.
**Use case:** Quickly create a new invoice based on an existing one,
useful for recurring invoices to the same customer.
**What is copied:**
- Customer data (recipient)
- Invoice lines (descriptions, quantities, prices, taxes)
- Payment method
- Series (if specified, otherwise uses default)
- Observations
**What is NOT copied (reset to defaults):**
- Invoice number (null - assigned when issued)
- Status (always DRAFT)
- Issue date (defaults to today, can be overridden)
- Due date (recalculated based on new issue date)
- VeriFactu data
- PDF
- Payment date
- Sent date
**Result:** A new draft invoice ready for review and emission.
**Note:** Send `Content-Type: application/json` even when body is empty.
## POST /v1/invoices/{invoice_id}/duplicate
**Duplicate invoice as draft**
Creates a copy of an existing invoice as a new draft.
**Use case:** Quickly create a new invoice based on an existing one,
useful for recurring invoices to the same customer.
**What is copied:**
- Customer data (recipient)
- Invoice lines (descriptions, quantities, prices, taxes)
- Payment method
- Series (if specified, otherwise uses default)
- Observations
**What is NOT copied (reset to defaults):**
- Invoice number (null - assigned when issued)
- Status (always DRAFT)
- Issue date (defaults to today, can be overridden)
- Due date (recalculated based on new issue date)
- VeriFactu data
- PDF
- Payment date
- Sent date
**Result:** A new draft invoice ready for review and emission.
**Note:** Send `Content-Type: application/json` even when body is empty.
### Parameters
- **invoice_id** (required) in path: ID of the invoice to duplicate
### Request Body
- **issue_date** `string` (date): Issue date for the new invoice.
If not provided, defaults to today.
- **series_id**: Series ID for the new invoice.
If not provided, uses the same series as the original.
- **notes** `string`: Observations for the new invoice.
If not provided, copies from the original invoice.
### Responses
#### 201: Invoice duplicated successfully as draft
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot duplicate invoice (e.g., invoice is deleted)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Original invoice not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Export invoices to Excel API Reference
Exports invoices to an Excel file (XLSX format).
**Two modes of operation:**
- **By IDs:** Export specific invoices by providing `invoice_ids`
- **By filters:** Export all invoices matching filter criteria
**Two export formats (like Holded):**
- **SUMMARY:** One row per invoice with aggregated totals (default)
- **ITEMS:** One row per invoice line item, ideal for import compatibility
**Columns for SUMMARY format:**
- Date, Number, Due Date, Customer, NIF
- Description, Subtotal, IVA, Withholding, Equivalence Surcharge
- Total, Collected, Pending, Status, Payment Method
**Columns for ITEMS format:**
- Invoice Number, Date, Due Date, Draft, Contact, Contact NIF
- Address, Postal Code, City, Province, Country
- SKU, Item, Units, Unit Price, Discount %
- Subtotal, Tax Type, Tax %, Tax Amount
- Surcharge %, Surcharge Amount, IRPF %, IRPF Amount, Total
**Limits:**
- Maximum 5000 invoices per export
- All invoices must belong to the authenticated user (RLS enforced)
**Usage example (Frontend):**
```javascript
const response = await fetch('/v1/invoices/export/excel', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ invoice_ids: [...], format: 'ITEMS' })
});
const blob = await response.blob();
// Download the blob as file
```
## POST /v1/invoices/export/excel
**Export invoices to Excel**
Exports invoices to an Excel file (XLSX format).
**Two modes of operation:**
- **By IDs:** Export specific invoices by providing `invoice_ids`
- **By filters:** Export all invoices matching filter criteria
**Two export formats (like Holded):**
- **SUMMARY:** One row per invoice with aggregated totals (default)
- **ITEMS:** One row per invoice line item, ideal for import compatibility
**Columns for SUMMARY format:**
- Date, Number, Due Date, Customer, NIF
- Description, Subtotal, IVA, Withholding, Equivalence Surcharge
- Total, Collected, Pending, Status, Payment Method
**Columns for ITEMS format:**
- Invoice Number, Date, Due Date, Draft, Contact, Contact NIF
- Address, Postal Code, City, Province, Country
- SKU, Item, Units, Unit Price, Discount %
- Subtotal, Tax Type, Tax %, Tax Amount
- Surcharge %, Surcharge Amount, IRPF %, IRPF Amount, Total
**Limits:**
- Maximum 5000 invoices per export
- All invoices must belong to the authenticated user (RLS enforced)
**Usage example (Frontend):**
```javascript
const response = await fetch('/v1/invoices/export/excel', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ invoice_ids: [...], format: 'ITEMS' })
});
const blob = await response.blob();
// Download the blob as file
```
### Request Body
- **invoice_ids** `array[UUID]`: List of specific invoice IDs to export.
If provided, filters are ignored.
- **format** `string`: Export format.
- **SUMMARY**: One row per invoice with totals (default)
- **ITEMS**: One row per invoice line item
- one of: SUMMARY, ITEMS
- **status**: No description
- **type**: No description
- **date_from** `string` (date): Issue date from (YYYY-MM-DD)
- **date_to** `string` (date): Issue date to (YYYY-MM-DD)
- **customer_id**: No description
- **recipient_name** `string`: Filter by recipient name (partial match)
- **recipient_nif** `string`: Filter by recipient NIF (partial match)
- **series_code** `string`: Filter by series code
### Responses
#### 200: Excel file generated successfully
#### 400: Invalid request (must provide invoice_ids or filters)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error (too many invoices, invalid filters)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## UUID
Universally Unique Identifier (UUID v4)
---
# Get invoice PDF download URL API Reference
Generates a temporary pre-signed URL to download the invoice PDF.
**Security:**
- URL expires automatically in 5 minutes
- HMAC signature prevents tampering
- Only allows download (GET), no modification
**Benefits:**
- Direct download from storage (bypasses backend)
- Better performance and lower server load
- Compatible with browser cache and CDN
- Ideal for large files
**Frontend usage:**
```javascript
const response = await fetch('/v1/invoices/{id}/pdf');
const { download_url } = await response.json();
window.open(download_url, '_blank'); // Direct download
```
**Format:** PDF is generated according to Spanish tax regulations.
## GET /v1/invoices/{invoice_id}/pdf
**Get invoice PDF download URL**
Generates a temporary pre-signed URL to download the invoice PDF.
**Security:**
- URL expires automatically in 5 minutes
- HMAC signature prevents tampering
- Only allows download (GET), no modification
**Benefits:**
- Direct download from storage (bypasses backend)
- Better performance and lower server load
- Compatible with browser cache and CDN
- Ideal for large files
**Frontend usage:**
```javascript
const response = await fetch('/v1/invoices/{id}/pdf');
const { download_url } = await response.json();
window.open(download_url, '_blank'); // Direct download
```
**Format:** PDF is generated according to Spanish tax regulations.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Responses
#### 200: Download URL generated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required) `object`:
- **download_url** (required) `string` (uri): Pre-signed URL to download the PDF (valid for 5 minutes) (example: "https://minio.beel.es/beel-invoices/invoices/user-uuid/factura-uuid.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...")
- **expires_in_seconds** (required) `integer`: Seconds until the URL expires (example: 300)
- **file_name** (required) `string`: Suggested filename for download (example: "factura_2025-001.pdf")
- **meta** (required) `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 400: PDF has not been generated yet
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get invoice by ID API Reference
Retrieves complete details of a specific invoice
## GET /v1/invoices/{invoice_id}
**Get invoice by ID**
Retrieves complete details of a specific invoice
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Responses
#### 200: Invoice retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Issue invoice (DRAFT → ISSUED) API Reference
Finalizes a draft invoice and marks it as issued.
**Status change:** `DRAFT` → `ISSUED`
**Actions performed:**
- Assigns definitive invoice number according to configured series
- Marks invoice as finalized (not modifiable)
- Prepares invoice for sending to customer
**Validations:**
- Invoice must be in DRAFT status
- All invoice data must be complete and valid
**Note:** After issuing, the invoice can be sent to the customer via
the `/invoices/{id}/send` endpoint
## POST /v1/invoices/{invoice_id}/issue
**Issue invoice (DRAFT → ISSUED)**
Finalizes a draft invoice and marks it as issued.
**Status change:** `DRAFT` → `ISSUED`
**Actions performed:**
- Assigns definitive invoice number according to configured series
- Marks invoice as finalized (not modifiable)
- Prepares invoice for sending to customer
**Validations:**
- Invoice must be in DRAFT status
- All invoice data must be complete and valid
**Note:** After issuing, the invoice can be sent to the customer via
the `/invoices/{id}/send` endpoint
### Parameters
- **invoice_id** (required) in path: Invoice ID
- **wait_for_pdf** (optional) in query: If `true`, waits for PDF generation and returns the URL in the response.
Adds ~1-2s latency but guarantees PDF is immediately available.
If `false` (default), PDF is generated asynchronously.
### Responses
#### 200: Invoice issued successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot issue invoice (invalid status or incomplete data)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Invoice cannot be issued (validation failed)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# List invoices API Reference
Returns a paginated list of invoices with optional filters
## GET /v1/invoices
**List invoices**
Returns a paginated list of invoices with optional filters
### Parameters
- **undefined** (optional): No description
- **undefined** (optional): No description
- **search** (optional) in query: Global search across invoice number, recipient name, recipient NIF, and series code (partial, case-insensitive)
- **status** (optional) in query: Filter by invoice status
- **type** (optional) in query: Filter by invoice type
- **customer_id** (optional) in query: Filter by customer UUID
- **date_from** (optional) in query: Issue date from (YYYY-MM-DD)
- **date_to** (optional) in query: Issue date to (YYYY-MM-DD)
- **invoice_number** (optional) in query: Search by invoice number (e.g., 2025/0001)
- **recipient_name** (optional) in query: Filter by recipient's fiscal name (partial, case-insensitive search)
- **recipient_nif** (optional) in query: Filter by recipient's NIF (partial search)
- **series_code** (optional) in query: Filter by series code
- **taxable_base_min** (optional) in query: Minimum taxable base
- **taxable_base_max** (optional) in query: Maximum taxable base
- **total_min** (optional) in query: Minimum invoice total
- **total_max** (optional) in query: Maximum invoice total
- **verifactu_status** (optional) in query: Filter by VeriFactu status. Special values:
- "NO_VERIFACTU": Invoices where VeriFactu is not enabled
- "PENDING": Invoices with VeriFactu enabled pending submission
- "ACCEPTED": Invoices submitted and accepted by AEAT
- "REJECTED": Invoices submitted and rejected by AEAT
- **sort_by** (optional) in query: Field to sort by (e.g., issue_date, invoice_number, invoice_total)
- **sort_order** (optional) in query: Sort direction
### Responses
#### 200: Invoice list retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **invoices** (required) `array[Invoice]`:
- **pagination** (required) `object`:
- **current_page** (required) `integer`: No description (example: 1)
- **total_pages** (required) `integer`: No description (example: 5)
- **total_items** (required) `integer`: No description (example: 87)
- **items_per_page** (required) `integer`: No description (example: 20)
- **has_next** `boolean`: No description
- **has_previous** `boolean`: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## Invoice
### Properties
- **id** (required) `string`: Unique invoice UUID
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
- **series** (required): No description
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
- **type** (required): No description
- **status** (required): No description
- **issue_date** (required) `string`: Invoice issue date
- **due_date** `string`: Payment due date (must be the same as or after `issue_date`)
- **payment_date** `string`: Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
- **sent_at** `string`: System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
- **paid_at** `string`: System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
- **auto_emit_after** `string`: Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
- **scheduled_for** `string`: Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
- **scheduled_action**: No description
- **issuer** (required): No description
- **recipient** (required): No description
- **lines** (required) `array`: No description
- **totals** (required): No description
- **payment_info**: No description
- **notes** `string`: Additional observations or notes (max: 1000)
- **rectified_invoice_id** `string`: UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices) (max: 500)
- **recurring_invoice_id** `string`: UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type**: No description
- **rectification_code**: No description
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
- **verifactu**: No description
- **attachments** `array`: No description
- **sending_history** `array`: No description
- **created_at** (required) `string`: No description
- **updated_at** (required) `string`: No description
- **deleted_at** `string`: No description
---
# Mark invoice as paid API Reference
Marks an invoice as paid.
**Status change:** `SENT` → `PAID`
**Note:** Send `Content-Type: application/json` even when body is empty.
## POST /v1/invoices/{invoice_id}/mark-paid
**Mark invoice as paid**
Marks an invoice as paid.
**Status change:** `SENT` → `PAID`
**Note:** Send `Content-Type: application/json` even when body is empty.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Request Body
- **payment_date** `string` (date): Payment date (defaults to today)
- **payment_method**: Payment details object (not a string enum). Example:
`{ "method": "BANK_TRANSFER", "iban": "ES9121000418450200051332" }`
### Responses
#### 200: Invoice marked as paid successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot mark as paid (invalid status)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Mark invoice as sent API Reference
Marks an invoice as sent manually.
**Use case:** When the invoice was sent via WhatsApp, paper, or any other
channel outside of the email system.
**Status change:** `ISSUED` → `SENT`
**Records:** Sets `sent_at` timestamp for tracking.
**Note:** Send `Content-Type: application/json` even when body is empty.
## POST /v1/invoices/{invoice_id}/mark-sent
**Mark invoice as sent**
Marks an invoice as sent manually.
**Use case:** When the invoice was sent via WhatsApp, paper, or any other
channel outside of the email system.
**Status change:** `ISSUED` → `SENT`
**Records:** Sets `sent_at` timestamp for tracking.
**Note:** Send `Content-Type: application/json` even when body is empty.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Request Body
- **sent_at** `string` (date-time): Custom timestamp for when the invoice was sent.
If not provided, the current time will be used.
### Responses
#### 200: Invoice marked as sent successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot mark as sent (invalid status - must be ISSUED)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Preview draft invoice PDF API Reference
Generates a PDF preview for a draft invoice and returns the binary content directly.
**Requirements:**
- Invoice must be in BORRADOR (draft) status
- The PDF shows "BORRADOR" as the invoice number
- No VeriFactu QR code is included
**Behavior:**
- PDF is generated on-the-fly (not stored)
- Each request regenerates the PDF (reflects latest draft changes)
- Response is `application/pdf` for direct browser preview
## GET /v1/invoices/{invoice_id}/pdf/preview
**Preview draft invoice PDF**
Generates a PDF preview for a draft invoice and returns the binary content directly.
**Requirements:**
- Invoice must be in BORRADOR (draft) status
- The PDF shows "BORRADOR" as the invoice number
- No VeriFactu QR code is included
**Behavior:**
- PDF is generated on-the-fly (not stored)
- Each request regenerates the PDF (reflects latest draft changes)
- Response is `application/pdf` for direct browser preview
### Parameters
- **invoice_id** (required) in path: Invoice ID (must be a draft)
### Responses
#### 200: PDF preview generated successfully
#### 400: Invoice is not in draft status
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Reschedule invoice API Reference
Changes the scheduled date for a scheduled invoice.
**Status:** Remains `SCHEDULED`
The new date must be today or in the future.
## PATCH /v1/invoices/{invoice_id}/reschedule
**Reschedule invoice**
Changes the scheduled date for a scheduled invoice.
**Status:** Remains `SCHEDULED`
The new date must be today or in the future.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Request Body
- **scheduled_for** (required) `string` (date): New date when the invoice should be processed
### Responses
#### 200: Invoice rescheduled successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot reschedule (invalid date or invoice state)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Revert invoice to issued status API Reference
Reverts an invoice from SENT to ISSUED status.
**Use case:** To correct errors when an invoice was marked as sent by mistake.
**Status change:** `SENT` → `ISSUED`
**Side effects:** Clears the `sent_at` timestamp.
## POST /v1/invoices/{invoice_id}/revert-to-issued
**Revert invoice to issued status**
Reverts an invoice from SENT to ISSUED status.
**Use case:** To correct errors when an invoice was marked as sent by mistake.
**Status change:** `SENT` → `ISSUED`
**Side effects:** Clears the `sent_at` timestamp.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Responses
#### 200: Invoice reverted to ISSUED successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot revert (invoice must be in SENT status)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Schedule invoice for future processing API Reference
Schedules a draft invoice to be automatically processed on a future date.
**Status change:** `DRAFT` → `SCHEDULED`
**Actions available:**
- `DRAFT`: Convert to draft for manual review on the scheduled date
- `ISSUE_AND_SEND`: Issue and send automatically on the scheduled date
## POST /v1/invoices/{invoice_id}/schedule
**Schedule invoice for future processing**
Schedules a draft invoice to be automatically processed on a future date.
**Status change:** `DRAFT` → `SCHEDULED`
**Actions available:**
- `DRAFT`: Convert to draft for manual review on the scheduled date
- `ISSUE_AND_SEND`: Issue and send automatically on the scheduled date
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Request Body
- **scheduled_for** (required) `string` (date): Date when the invoice should be processed (must be today or future)
- **action**: No description
### Responses
#### 200: Invoice scheduled successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot schedule (invalid date or invoice state)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Send invoice by email API Reference
Sends the invoice by email to the customer.
**Email:** Sent to the billing emails configured for the customer.
**Attachments:** Includes the invoice PDF.
## POST /v1/invoices/{invoice_id}/send
**Send invoice by email**
Sends the invoice by email to the customer.
**Email:** Sent to the billing emails configured for the customer.
**Attachments:** Includes the invoice PDF.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Request Body
- **recipients** `array[Email]`: If not specified, uses the customer's email
- **cc** `array[Email]`:
- **subject** `string`: Email subject (optional, if not specified uses a default)
- **message** `string`: Custom message (optional, added before standard message)
- **attach_pdf** `boolean`: No description
- **language**: No description
### Responses
#### 200: Email sent successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **email_id** `string`: Universally Unique Identifier (UUID v4)
- **sent_to** `array[Email]`:
- **sent_at** `string` (date-time): No description
#### 400: Customer has no configured emails
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## Email
Email address (minimum valid email is 5 chars, e.g. a@b.co)
---
# Send multiple invoices by email API Reference
Sends multiple invoices by email to the specified recipients.
**Limits:**
- Maximum 20 invoices per request
- Maximum 25MB total attachment size
**Email behavior:**
- Single email with all PDFs as attachments
- Uses BULK_INVOICES template
**Validations:**
- Invoices must have status ISSUED, PAID, SENT or OVERDUE (not DRAFT or VOIDED)
- At least one recipient required (from request or user's accountant email)
**Partial success:** If some invoices cannot be attached, the email will
still be sent with available PDFs. Response includes `failures` array.
## POST /v1/invoices/bulk/send
**Send multiple invoices by email**
Sends multiple invoices by email to the specified recipients.
**Limits:**
- Maximum 20 invoices per request
- Maximum 25MB total attachment size
**Email behavior:**
- Single email with all PDFs as attachments
- Uses BULK_INVOICES template
**Validations:**
- Invoices must have status ISSUED, PAID, SENT or OVERDUE (not DRAFT or VOIDED)
- At least one recipient required (from request or user's accountant email)
**Partial success:** If some invoices cannot be attached, the email will
still be sent with available PDFs. Response includes `failures` array.
### Request Body
- **invoice_ids** (required) `array[UUID]`: List of invoice IDs to send
- **recipients** `array[Email]`: Email recipients. If not provided, uses accountant email from user profile.
- **cc** `array[Email]`: CC recipients
- **subject** `string`: Custom email subject. If not provided, uses default template.
- **message** `string`: Custom message body. If not provided, uses default template.
- **language**: Email language. If not provided, uses user's language.
### Responses
#### 200: Email sent successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **email_id** (required) `string`: Universally Unique Identifier (UUID v4)
- **sent_to** (required) `array[Email]`:
- **sent_at** (required) `string` (date-time): No description
- **total_invoices** (required) `integer`: Total number of requested invoices
- **invoices_attached** (required) `integer`: Number of PDFs successfully attached
- **failures** `array[object]`: List of invoices that could not be attached
- **invoice_id** `string`: Universally Unique Identifier (UUID v4)
- **error_code** `string`: No description - one of: NOT_FOUND, PDF_NOT_GENERATED, INVALID_STATUS, INTERNAL_ERROR
- **error_message** `string`: No description
#### 400: No valid invoices to send or no recipients specified
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error (too many invoices, invalid recipients)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## UUID
Universally Unique Identifier (UUID v4)
## Email
Email address (minimum valid email is 5 chars, e.g. a@b.co)
---
# Cancel scheduled invoice API Reference
Cancels a scheduled invoice and converts it back to draft.
**Status change:** `SCHEDULED` → `DRAFT`
The invoice can then be edited or manually issued.
## POST /v1/invoices/{invoice_id}/unschedule
**Cancel scheduled invoice**
Cancels a scheduled invoice and converts it back to draft.
**Status change:** `SCHEDULED` → `DRAFT`
The invoice can then be edited or manually issued.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Responses
#### 200: Invoice unscheduled successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot unschedule (invoice must be in SCHEDULED status)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Update invoice API Reference
Updates an existing draft invoice.
**Restriction:** Only invoices in `DRAFT` status can be modified.
## PUT /v1/invoices/{invoice_id}
**Update invoice**
Updates an existing draft invoice.
**Restriction:** Only invoices in `DRAFT` status can be modified.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Request Body
- **series_id**: Series ID. If provided, changes the invoice series (only for DRAFT invoices).
The invoice number will be reassigned from the new series when issued.
- **issue_date** `string` (date): No description
- **due_date** `string` (date): New due date. Must be the same as or after `issue_date`.
- **recipient**: No description
- **lines** `array[object]`:
- **description** (required) `string`: No description
- **quantity** (required) `number`: No description
- **unit** `string`: No description
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
- **discount_percentage** `number`: No description
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **payment_info**: No description
- **notes** `string`: No description
### Responses
#### 200: Invoice updated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Invalid JSON format — a field has a wrong type or format (e.g. invalid date, unknown enum value, malformed UUID).
The `details` object contains `field`, `invalid_value`, and optionally `expected_format` or `allowed_values`.
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **error**: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Void invoice API Reference
Voids an invoice by changing its status to `VOIDED`.
**Status change:** `ISSUED`, `SENT`, `OVERDUE`, `PAID` or `RECTIFIED` → `VOIDED`
**Use when:** The operation never took place (invoice issued by mistake, duplicate, etc.)
For invoices already submitted to VeriFactu, the cancellation is sent to AEAT automatically.
**Note:** If the operation did take place but with errors, use the corrective invoice endpoint instead.
## POST /v1/invoices/{invoice_id}/void
**Void invoice**
Voids an invoice by changing its status to `VOIDED`.
**Status change:** `ISSUED`, `SENT`, `OVERDUE`, `PAID` or `RECTIFIED` → `VOIDED`
**Use when:** The operation never took place (invoice issued by mistake, duplicate, etc.)
For invoices already submitted to VeriFactu, the cancellation is sent to AEAT automatically.
**Note:** If the operation did take place but with errors, use the corrective invoice endpoint instead.
### Parameters
- **invoice_id** (required) in path: Invoice ID
### Request Body
- **reason** (required) `string`: Void reason (minimum 10 characters)
- **void_date** `string` (date): Void date (defaults to today)
### Responses
#### 200: Invoice voided successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 400: Cannot void invoice (invalid status or incorrect data)
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Validate NIF against AEAT registry API Reference
**Public endpoint** to validate a NIF/CIF against the AEAT registry using VeriFactu.
This endpoint is useful for:
- Pre-validation before registration (proactive feedback)
- Validating customer NIFs before creating invoices
- Verifying that a NIF exists in the registry
**Behavior:**
- **VALID**: The NIF exists in the AEAT registry. Returns the fiscal name.
- **INVALID**: The NIF has correct format but doesn't exist in the registry.
- **PENDING**: VeriFactu API is temporarily unavailable. The NIF has valid syntax but couldn't be verified against the registry.
- **ERROR**: Technical error during validation (invalid syntax, timeout, etc.)
**Note about PENDING:**
If you use this endpoint for pre-validation during registration, a PENDING status
indicates that the NIF has valid format and the user can continue. The system
will validate the NIF automatically when the service becomes available.
**Rate limiting:**
- With API Key: 100 requests/hour
- With Session Cookie: 1000 requests/hour
**Authentication:**
This endpoint accepts both API Keys and Session Cookies.
## POST /v1/nif/validate
**Validate NIF against AEAT registry**
**Public endpoint** to validate a NIF/CIF against the AEAT registry using VeriFactu.
This endpoint is useful for:
- Pre-validation before registration (proactive feedback)
- Validating customer NIFs before creating invoices
- Verifying that a NIF exists in the registry
**Behavior:**
- **VALID**: The NIF exists in the AEAT registry. Returns the fiscal name.
- **INVALID**: The NIF has correct format but doesn't exist in the registry.
- **PENDING**: VeriFactu API is temporarily unavailable. The NIF has valid syntax but couldn't be verified against the registry.
- **ERROR**: Technical error during validation (invalid syntax, timeout, etc.)
**Note about PENDING:**
If you use this endpoint for pre-validation during registration, a PENDING status
indicates that the NIF has valid format and the user can continue. The system
will validate the NIF automatically when the service becomes available.
**Rate limiting:**
- With API Key: 100 requests/hour
- With Session Cookie: 1000 requests/hour
**Authentication:**
This endpoint accepts both API Keys and Session Cookies.
### Request Body
- **nif** (required): No description
- **legal_name** `string`: 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)
AEAT validates that the provided name matches the one registered in the census.
If it doesn't match, validation will return INVALID.
### Responses
#### 200: Validation result
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **valid** (required) `boolean`: true if the NIF is validated against the AEAT census (status = VALID).
false otherwise.
(example: true)
- **status** (required): No description
- **legal_name** `string`: Legal name obtained from the AEAT census.
Only available if status = VALID.
(example: "JUAN PEREZ GARCIA")
- **message** (required) `string`: Descriptive message of the validation result.
Examples:
- VALID: "NIF successfully validated against the AEAT census"
- INVALID: "NIF does not exist in the AEAT census"
- PENDING: "NIF validation is pending. The system will automatically validate it when the service is available."
- ERROR: "Error validating NIF: VeriFactu API timeout"
(example: "NIF successfully validated against the AEAT census")
- **validated_at** `string` (date-time): Timestamp of when the NIF was successfully validated.
Only available if status = VALID.
(example: "2025-01-15T10:30:00Z")
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get invoice customization options API Reference
Retrieves available option catalogs to customize invoices:
**Template types:**
- MODERN_TABLE: Structured table design, ideal for standard products/services
- PROFESSIONAL_SERVICE: Text-based design, ideal for notaries/consultancies
**Suggested color palette:**
- BeeL default colors (orange, blue)
- Professional palette (dark grays)
- Creative palette (violet, pink, amber, emerald green)
- Classic palette (blue, red, green, purple)
**Usage:**
User can choose a template and accent color to customize
their invoices. These values are saved in their profile and automatically applied
when generating new invoice PDFs.
Template and color names are returned translated to the user's invoice language preference.
## GET /v1/configuration/invoice-customization-options
**Get invoice customization options**
Retrieves available option catalogs to customize invoices:
**Template types:**
- MODERN_TABLE: Structured table design, ideal for standard products/services
- PROFESSIONAL_SERVICE: Text-based design, ideal for notaries/consultancies
**Suggested color palette:**
- BeeL default colors (orange, blue)
- Professional palette (dark grays)
- Creative palette (violet, pink, amber, emerald green)
- Classic palette (blue, red, green, purple)
**Usage:**
User can choose a template and accent color to customize
their invoices. These values are saved in their profile and automatically applied
when generating new invoice PDFs.
Template and color names are returned translated to the user's invoice language preference.
### Responses
#### 200: Customization options retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **template_types** (required) `array[InvoiceTemplateOption]`: Available template types
- **suggested_colors** (required) `array[ColorOption]`: Suggested color palette
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceTemplateOption
### Properties
- **code** (required) `string`: Unique template code - one of: MODERN_TABLE, PROFESSIONAL_SERVICE
- **name** (required) `string`: Descriptive template name
- **description** (required) `string`: Detailed template description
- **preview_url** `string`: URL to a template preview image
- **features** (required) `array`: List of template features
- **template_html** (required) `string`: Complete HTML template with {{variable}} placeholders not replaced.
The frontend will use this HTML to render previews by replacing:
- {{language}} - Document language (es, en, ca)
- {{numeroFactura}}, {{fechaEmision}}, {{fechaVencimiento}}
- {{emisorNombre}}, {{emisorNif}}, {{emisorDireccion}}, {{emisorEmail}}
- {{receptorNombre}}, {{receptorNif}}, {{receptorDireccion}}, {{receptorEmail}}
- {{logoHtml}}, {{qrHtml}}, {{rectificativaBanner}}
- {{tableHeaderHtml}}, {{lineasHtml}}
- {{baseImponible}}, {{ivaRow}}, {{recargoRow}}, {{irpfRow}}, {{totalFactura}}
- {{metodoPago}}, {{ibanHtml}}, {{observacionesHtml}}
- {{primaryColor}}, {{primaryColorLight}}
## ColorOption
### Properties
- **hex** (required) `string`: Color in hexadecimal format
- **name** (required) `string`: Descriptive color name
- **category** (required) `string`: Color category:
- DEFAULT: BeeL brand colors
- PROFESSIONAL: Professional tones (grays, dark blues)
- CREATIVE: Striking colors (violet, pink, amber)
- CLASSIC: Classic colors (blue, red, green, purple)
- one of: DEFAULT, PROFESSIONAL, CREATIVE, CLASSIC
---
# Update user preferred language API Reference
Updates the authenticated user's preferred language.
This language is used for:
- UI translations
- Template names and colors in invoice customization
- Emails sent to the user
**Supported languages:**
- `es` - Spanish (default)
- `en` - English
- `ca` - Catalan
## PUT /v1/configuration/language
**Update user preferred language**
Updates the authenticated user's preferred language.
This language is used for:
- UI translations
- Template names and colors in invoice customization
- Emails sent to the user
**Supported languages:**
- `es` - Spanish (default)
- `en` - English
- `ca` - Catalan
### Request Body
- **language** (required): No description
### Responses
#### 200: Language updated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **language** `string`: Supported languages
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Create new product/service API Reference
Creates a new product or service in the catalog
## POST /v1/products
**Create new product/service**
Creates a new product or service in the catalog
### Parameters
- **Idempotency-Key** (optional) in header: Idempotency key to prevent duplicates
### Request Body
- **code** `string`: Unique alphanumeric product code (optional)
- **name** (required) `string`: Product/service name
- **description** `string`: Detailed description (optional)
- **category**: No description
- **default_price** `number`: Suggested default price (optional)
- **unit** `string`: Unit of measure (optional)
- **main_tax**: No description
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional)
- **irpf** `number`: IRPF withholding percentage (optional)
### Responses
#### 201: Product created successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique UUID of the product/service (example: "550e8400-e29b-41d4-a716-446655440000")
- **code** `string`: Unique alphanumeric product code (optional) (example: "SERV-001")
- **name** (required) `string`: Product/service name (example: "Technical consulting")
- **description** `string`: Detailed product/service description (optional) (example: "Specialized technical consulting services in web development")
- **category** (required) `string`: Product/service category:
* PRODUCT - Physical, tangible products
* SERVICE - General services
* CONSULTING - Consulting and advisory services
* SOFTWARE - Development, licenses, SaaS
* TRAINING - Courses, workshops, training
* OTHER - Other unclassified types
- **default_price** `number`: Suggested default price (optional) (example: 85.5)
- **unit** `string`: Unit of measure (optional) (example: "hours")
- **main_tax** (required) `object`: Complete tax information with cross-validations:
- IVA: only percentages 0, 4, 10, 21
- IGIC: only percentages 0, 3, 5, 7, 9.5, 15, 20
- IPSI: only percentages 0.5, 1, 2, 4, 8, 10
- OTHER: any percentage between 0 and 100
- **type** (required) `string`: Tax type by territory:
- IVA: Iberian Peninsula and Balearic Islands (0%, 4%, 10%, 21%)
- IGIC: Canary Islands (0%, 3%, 5%, 7%, 9.5%, 15%, 20%)
- IPSI: Ceuta and Melilla (0.5%, 1%, 2%, 4%, 8%, 10%)
- OTHER: Configurable 0%-100%
- **percentage** (required) `number`: Tax percentage (example: 21)
- **regime_key** `string`: Regime key according to VeriFactu regulations:
- 01: General regime operation
- 02: Export
- 03: Used goods, art, antiques
- 04: Investment gold
- 05: Travel agencies
- 06: Group of entities
- 07: Cash basis
- 08: IPSI/IVA/IGIC operations
- 09: Mediating agencies
- 10: Third-party collections
- 11: Local rental
- 14: VAT pending in certifications
- 15: VAT pending successive tract
- 17: OSS and IOSS
- 18: Equivalence surcharge
- 19: REAGYP
- 20: Simplified regime
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional) (example: 5.2)
- **irpf** `number`: IRPF withholding percentage (optional) (example: 15)
- **active** (required) `boolean`: Indicates whether the product is active (example: true)
- **created_at** (required) `string` (date-time): Creation date and time (example: "2025-01-18T10:30:00Z")
- **updated_at** (required) `string` (date-time): Last update date and time (example: "2025-01-18T15:45:30Z")
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 409: Duplicate code or request already processed
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Unprocessable entity - validation or business rule error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Create multiple products API Reference
Creates multiple products in one operation (max 100)
## POST /v1/products/bulk
**Create multiple products**
Creates multiple products in one operation (max 100)
### Parameters
- **Idempotency-Key** (optional) in header: Idempotency key for the entire operation
### Request Body
- **products** (required) `array[CreateProductRequest]`:
### Responses
#### 200: Bulk operation completed
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **created_products** `array[Product]`:
- **errors** `array[object]`:
- **index** `integer`: No description
- **code** `string`: No description
- **name** `string`: No description
- **error** `string`: No description
- **summary** `object`:
- **total_processed** `integer`: No description
- **successful** `integer`: No description
- **failed** `integer`: No description
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 413: Payload too large
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## CreateProductRequest
### Properties
- **code** `string`: Unique alphanumeric product code (optional) (max: 50)
- **name** (required) `string`: Product/service name (max: 255)
- **description** `string`: Detailed description (optional)
- **category**: No description
- **default_price** `number`: Suggested default price (optional) (min: 0)
- **unit** `string`: Unit of measure (optional) (max: 50)
- **main_tax**: No description
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional) (min: 0) (max: 100)
- **irpf** `number`: IRPF withholding percentage (optional) (min: 0) (max: 100)
## Product
### Properties
- **id** (required) `string`: Unique UUID of the product/service
- **code** `string`: Unique alphanumeric product code (optional) (max: 50)
- **name** (required) `string`: Product/service name (max: 255)
- **description** `string`: Detailed product/service description (optional)
- **category** (required): No description
- **default_price** `number`: Suggested default price (optional) (min: 0)
- **unit** `string`: Unit of measure (optional) (max: 50)
- **main_tax** (required): No description
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional) (min: 0) (max: 100)
- **irpf** `number`: IRPF withholding percentage (optional) (min: 0) (max: 100)
- **active** (required) `boolean`: Indicates whether the product is active
- **created_at** (required) `string`: Creation date and time
- **updated_at** (required) `string`: Last update date and time
---
# Delete product API Reference
Deletes a product from catalog
## DELETE /v1/products/{product_id}
**Delete product**
Deletes a product from catalog
### Responses
#### 204: Product deleted successfully
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Delete multiple products API Reference
Deletes multiple products from catalog (max 100)
## DELETE /v1/products/bulk
**Delete multiple products**
Deletes multiple products from catalog (max 100)
### Request Body
- **product_ids** (required) `array[string]`:
### Responses
#### 200: Bulk delete operation completed
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **deleted_products** `array[string]`:
- **errors** `array[object]`:
- **product_id** `string` (uuid): No description
- **error** `string`: No description
- **summary** `object`:
- **total_processed** `integer`: No description
- **successful** `integer`: No description
- **failed** `integer`: No description
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 413: Payload too large
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get product by ID API Reference
Retrieves details of a specific product
## GET /v1/products/{product_id}
**Get product by ID**
Retrieves details of a specific product
### Responses
#### 200: Product retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique UUID of the product/service (example: "550e8400-e29b-41d4-a716-446655440000")
- **code** `string`: Unique alphanumeric product code (optional) (example: "SERV-001")
- **name** (required) `string`: Product/service name (example: "Technical consulting")
- **description** `string`: Detailed product/service description (optional) (example: "Specialized technical consulting services in web development")
- **category** (required) `string`: Product/service category:
* PRODUCT - Physical, tangible products
* SERVICE - General services
* CONSULTING - Consulting and advisory services
* SOFTWARE - Development, licenses, SaaS
* TRAINING - Courses, workshops, training
* OTHER - Other unclassified types
- **default_price** `number`: Suggested default price (optional) (example: 85.5)
- **unit** `string`: Unit of measure (optional) (example: "hours")
- **main_tax** (required) `object`: Complete tax information with cross-validations:
- IVA: only percentages 0, 4, 10, 21
- IGIC: only percentages 0, 3, 5, 7, 9.5, 15, 20
- IPSI: only percentages 0.5, 1, 2, 4, 8, 10
- OTHER: any percentage between 0 and 100
- **type** (required) `string`: Tax type by territory:
- IVA: Iberian Peninsula and Balearic Islands (0%, 4%, 10%, 21%)
- IGIC: Canary Islands (0%, 3%, 5%, 7%, 9.5%, 15%, 20%)
- IPSI: Ceuta and Melilla (0.5%, 1%, 2%, 4%, 8%, 10%)
- OTHER: Configurable 0%-100%
- **percentage** (required) `number`: Tax percentage (example: 21)
- **regime_key** `string`: Regime key according to VeriFactu regulations:
- 01: General regime operation
- 02: Export
- 03: Used goods, art, antiques
- 04: Investment gold
- 05: Travel agencies
- 06: Group of entities
- 07: Cash basis
- 08: IPSI/IVA/IGIC operations
- 09: Mediating agencies
- 10: Third-party collections
- 11: Local rental
- 14: VAT pending in certifications
- 15: VAT pending successive tract
- 17: OSS and IOSS
- 18: Equivalence surcharge
- 19: REAGYP
- 20: Simplified regime
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional) (example: 5.2)
- **irpf** `number`: IRPF withholding percentage (optional) (example: 15)
- **active** (required) `boolean`: Indicates whether the product is active (example: true)
- **created_at** (required) `string` (date-time): Creation date and time (example: "2025-01-18T10:30:00Z")
- **updated_at** (required) `string` (date-time): Last update date and time (example: "2025-01-18T15:45:30Z")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# List products/services from catalog API Reference
Returns a paginated list of products/services with optional filters
## GET /v1/products
**List products/services from catalog**
Returns a paginated list of products/services with optional filters
### Parameters
- **undefined** (optional): No description
- **undefined** (optional): No description
- **category** (optional) in query: Filter by product category
- **active** (optional) in query: Filter by active/inactive status
- **search** (optional) in query: Global search by name, code or description
- **name** (optional) in query: Filter by name (partial search case-insensitive)
- **code** (optional) in query: Filter by code (partial search)
- **min_price** (optional) in query: Minimum price
- **max_price** (optional) in query: Maximum price
- **sort_by** (optional) in query: Field to sort by
- **sort_order** (optional) in query: Sort order direction
### Responses
#### 200: Product list retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **products** (required) `array[Product]`:
- **pagination** (required) `object`:
- **current_page** (required) `integer`: No description (example: 1)
- **total_pages** (required) `integer`: No description (example: 5)
- **total_items** (required) `integer`: No description (example: 87)
- **items_per_page** (required) `integer`: No description (example: 20)
- **has_next** `boolean`: No description
- **has_previous** `boolean`: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## Product
### Properties
- **id** (required) `string`: Unique UUID of the product/service
- **code** `string`: Unique alphanumeric product code (optional) (max: 50)
- **name** (required) `string`: Product/service name (max: 255)
- **description** `string`: Detailed product/service description (optional)
- **category** (required): No description
- **default_price** `number`: Suggested default price (optional) (min: 0)
- **unit** `string`: Unit of measure (optional) (max: 50)
- **main_tax** (required): No description
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional) (min: 0) (max: 100)
- **irpf** `number`: IRPF withholding percentage (optional) (min: 0) (max: 100)
- **active** (required) `boolean`: Indicates whether the product is active
- **created_at** (required) `string`: Creation date and time
- **updated_at** (required) `string`: Last update date and time
---
# Search and autocomplete API Reference
Optimized endpoint for active product autocomplete
## GET /v1/products/search
**Search and autocomplete**
Optimized endpoint for active product autocomplete
### Parameters
- **q** (optional) in query: Search term (empty to get recent products)
- **limit** (optional) in query: Result limit (max 20)
### Responses
#### 200: Search results retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `array[Product]`:
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## Product
### Properties
- **id** (required) `string`: Unique UUID of the product/service
- **code** `string`: Unique alphanumeric product code (optional) (max: 50)
- **name** (required) `string`: Product/service name (max: 255)
- **description** `string`: Detailed product/service description (optional)
- **category** (required): No description
- **default_price** `number`: Suggested default price (optional) (min: 0)
- **unit** `string`: Unit of measure (optional) (max: 50)
- **main_tax** (required): No description
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional) (min: 0) (max: 100)
- **irpf** `number`: IRPF withholding percentage (optional) (min: 0) (max: 100)
- **active** (required) `boolean`: Indicates whether the product is active
- **created_at** (required) `string`: Creation date and time
- **updated_at** (required) `string`: Last update date and time
---
# Update product API Reference
Updates an existing product
## PUT /v1/products/{product_id}
**Update product**
Updates an existing product
### Request Body
- **code** `string`: Unique alphanumeric product code (optional)
- **name** `string`: Product/service name
- **description** `string`: Detailed description (optional)
- **category**: No description
- **default_price** `number`: Suggested default price (optional)
- **unit** `string`: Unit of measure (optional)
- **main_tax**: No description
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional)
- **irpf** `number`: IRPF withholding percentage (optional)
- **active** `boolean`: Indicates whether the product is active
### Responses
#### 200: Product updated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique UUID of the product/service (example: "550e8400-e29b-41d4-a716-446655440000")
- **code** `string`: Unique alphanumeric product code (optional) (example: "SERV-001")
- **name** (required) `string`: Product/service name (example: "Technical consulting")
- **description** `string`: Detailed product/service description (optional) (example: "Specialized technical consulting services in web development")
- **category** (required) `string`: Product/service category:
* PRODUCT - Physical, tangible products
* SERVICE - General services
* CONSULTING - Consulting and advisory services
* SOFTWARE - Development, licenses, SaaS
* TRAINING - Courses, workshops, training
* OTHER - Other unclassified types
- **default_price** `number`: Suggested default price (optional) (example: 85.5)
- **unit** `string`: Unit of measure (optional) (example: "hours")
- **main_tax** (required) `object`: Complete tax information with cross-validations:
- IVA: only percentages 0, 4, 10, 21
- IGIC: only percentages 0, 3, 5, 7, 9.5, 15, 20
- IPSI: only percentages 0.5, 1, 2, 4, 8, 10
- OTHER: any percentage between 0 and 100
- **type** (required) `string`: Tax type by territory:
- IVA: Iberian Peninsula and Balearic Islands (0%, 4%, 10%, 21%)
- IGIC: Canary Islands (0%, 3%, 5%, 7%, 9.5%, 15%, 20%)
- IPSI: Ceuta and Melilla (0.5%, 1%, 2%, 4%, 8%, 10%)
- OTHER: Configurable 0%-100%
- **percentage** (required) `number`: Tax percentage (example: 21)
- **regime_key** `string`: Regime key according to VeriFactu regulations:
- 01: General regime operation
- 02: Export
- 03: Used goods, art, antiques
- 04: Investment gold
- 05: Travel agencies
- 06: Group of entities
- 07: Cash basis
- 08: IPSI/IVA/IGIC operations
- 09: Mediating agencies
- 10: Third-party collections
- 11: Local rental
- 14: VAT pending in certifications
- 15: VAT pending successive tract
- 17: OSS and IOSS
- 18: Equivalence surcharge
- 19: REAGYP
- 20: Simplified regime
- **equivalence_surcharge** `number`: Equivalence surcharge percentage (optional) (example: 5.2)
- **irpf** `number`: IRPF withholding percentage (optional) (example: 15)
- **active** (required) `boolean`: Indicates whether the product is active (example: true)
- **created_at** (required) `string` (date-time): Creation date and time (example: "2025-01-18T10:30:00Z")
- **updated_at** (required) `string` (date-time): Last update date and time (example: "2025-01-18T15:45:30Z")
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 409: Duplicate code
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Unprocessable entity - validation or business rule error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Create a recurring invoice from an existing invoice API Reference
Creates a new recurring invoice template using the lines, recipient, and configuration from an existing invoice.
## POST /v1/invoices/{invoice_id}/create-recurring
**Create a recurring invoice from an existing invoice**
Creates a new recurring invoice template using the lines, recipient, and configuration from an existing invoice.
### Parameters
- **invoice_id** (required) in path: No description
### Request Body
- **name** (required) `string`: No description
- **day_of_month** (required) `integer`: No description
- **start_date** (required) `string` (date): No description
- **end_date** `string` (date): No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration**: No description
### Responses
#### 201: Recurring invoice created from existing invoice
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **frequency** `string`: No description - one of: MONTHLY
- **day_of_month** `integer`: No description
- **start_date** `string` (date): No description
- **end_date** `string` (date): No description
- **next_generation** `string` (date): No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission. (example: 3)
- **status** `string`: No description - one of: ACTIVE, PAUSED, COMPLETED
- **series_id** `string` (uuid): No description
- **series_code** `string`: No description
- **invoice_type** `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string` (uuid): No description
- **recipient_fiscal_name** `string`: No description
- **recipient_nif** `string`: No description
- **lines** `array[InvoiceLineTemplateResponse]`:
- **payment_method** `string`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration** `object`:
- **recipients** `array[string]`:
- **cc** `array[string]`:
- **subject** `string`: No description
- **message** `string`: No description
- **generated_invoices** `integer`: No description
- **last_generation** `string` (date-time): No description
- **source_invoice_id** `string` (uuid): No description
- **created_at** `string` (date-time): No description
- **updated_at** `string` (date-time): No description
#### 403: Insufficient permissions
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLineTemplateResponse
### Properties
- **id** `string`: No description
- **order** `integer`: No description
- **description** `string`: No description
- **quantity** `number`: No description
- **unit** `string`: No description
- **unit_price** `number`: No description
- **discount_percentage** `number`: No description
- **tax_type** `string`: No description
- **vat_rate** `number`: No description
- **regime_key** `string`: No description
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
---
# Create a recurring invoice from scratch API Reference
Creates a new recurring invoice template with all template data (lines, recipient, series, payment) and recurrence configuration, without needing an existing invoice.
## POST /v1/recurring-invoices
**Create a recurring invoice from scratch**
Creates a new recurring invoice template with all template data (lines, recipient, series, payment) and recurrence configuration, without needing an existing invoice.
### Request Body
- **name** (required) `string`: No description
- **day_of_month** (required) `integer`: No description
- **start_date** (required) `string` (date): No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission.
- **end_date** `string` (date): No description
- **series_id** (required) `string` (uuid): No description
- **invoice_type** (required) `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string` (uuid): No description
- **lines** (required) `array[RecurringLineRequest]`:
- **payment_method**: No description
- **payment_iban** `string`: No description
- **payment_swift** `string`: No description
- **payment_term_days** `integer`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration**: No description
### Responses
#### 201: Recurring invoice created successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **frequency** `string`: No description - one of: MONTHLY
- **day_of_month** `integer`: No description
- **start_date** `string` (date): No description
- **end_date** `string` (date): No description
- **next_generation** `string` (date): No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission. (example: 3)
- **status** `string`: No description - one of: ACTIVE, PAUSED, COMPLETED
- **series_id** `string` (uuid): No description
- **series_code** `string`: No description
- **invoice_type** `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string` (uuid): No description
- **recipient_fiscal_name** `string`: No description
- **recipient_nif** `string`: No description
- **lines** `array[InvoiceLineTemplateResponse]`:
- **payment_method** `string`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration** `object`:
- **recipients** `array[string]`:
- **cc** `array[string]`:
- **subject** `string`: No description
- **message** `string`: No description
- **generated_invoices** `integer`: No description
- **last_generation** `string` (date-time): No description
- **source_invoice_id** `string` (uuid): No description
- **created_at** `string` (date-time): No description
- **updated_at** `string` (date-time): No description
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## RecurringLineRequest
### Properties
- **description** (required) `string`: No description (max: 500)
- **quantity** (required) `number`: No description (min: 0.01)
- **unit** `string`: No description (max: 20)
- **unit_price** (required) `number`: No description (min: 0)
- **discount_percentage** `number`: No description (min: 0) (max: 100)
- **tax_type** `string`: No description (default: IVA)
- **vat_rate** (required) `number`: No description
- **regime_key** `string`: No description (default: 01)
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
## InvoiceLineTemplateResponse
### Properties
- **id** `string`: No description
- **order** `integer`: No description
- **description** `string`: No description
- **quantity** `number`: No description
- **unit** `string`: No description
- **unit_price** `number`: No description
- **discount_percentage** `number`: No description
- **tax_type** `string`: No description
- **vat_rate** `number`: No description
- **regime_key** `string`: No description
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
---
# Delete a recurring invoice API Reference
Permanently deletes a recurring invoice and cancels any pending scheduled generations.
## DELETE /v1/recurring-invoices/{recurring_invoice_id}
**Delete a recurring invoice**
Permanently deletes a recurring invoice and cancels any pending scheduled generations.
### Parameters
- **recurring_invoice_id** (required) in path: No description
### Responses
#### 204: Recurring invoice deleted successfully
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Generate an invoice now from a recurring template API Reference
Manually triggers invoice generation from a recurring template.
## POST /v1/recurring-invoices/{recurring_invoice_id}/generate
**Generate an invoice now from a recurring template**
Manually triggers invoice generation from a recurring template.
### Parameters
- **recurring_invoice_id** (required) in path: No description
### Responses
#### 201: Invoice generated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **invoice_id** `string` (uuid): No description
#### 400: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get generation history for a recurring invoice API Reference
Returns the list of invoices previously generated from this recurring template, including their status and generation dates.
## GET /v1/recurring-invoices/{recurring_invoice_id}/history
**Get generation history for a recurring invoice**
Returns the list of invoices previously generated from this recurring template, including their status and generation dates.
### Parameters
- **recurring_invoice_id** (required) in path: No description
### Responses
#### 200: Generation history retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `array[GenerationHistoryResponse]`:
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## GenerationHistoryResponse
### Properties
- **id** `string`: No description
- **invoice_id** `string`: No description
- **generated_at** `string`: No description
- **scheduled_date** `string`: No description
---
# Get a recurring invoice by ID API Reference
Retrieves the full details of a recurring invoice including its schedule, template lines, and next generation date.
## GET /v1/recurring-invoices/{recurring_invoice_id}
**Get a recurring invoice by ID**
Retrieves the full details of a recurring invoice including its schedule, template lines, and next generation date.
### Parameters
- **recurring_invoice_id** (required) in path: No description
### Responses
#### 200: Recurring invoice retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **frequency** `string`: No description - one of: MONTHLY
- **day_of_month** `integer`: No description
- **start_date** `string` (date): No description
- **end_date** `string` (date): No description
- **next_generation** `string` (date): No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission. (example: 3)
- **status** `string`: No description - one of: ACTIVE, PAUSED, COMPLETED
- **series_id** `string` (uuid): No description
- **series_code** `string`: No description
- **invoice_type** `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string` (uuid): No description
- **recipient_fiscal_name** `string`: No description
- **recipient_nif** `string`: No description
- **lines** `array[InvoiceLineTemplateResponse]`:
- **payment_method** `string`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration** `object`:
- **recipients** `array[string]`:
- **cc** `array[string]`:
- **subject** `string`: No description
- **message** `string`: No description
- **generated_invoices** `integer`: No description
- **last_generation** `string` (date-time): No description
- **source_invoice_id** `string` (uuid): No description
- **created_at** `string` (date-time): No description
- **updated_at** `string` (date-time): No description
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLineTemplateResponse
### Properties
- **id** `string`: No description
- **order** `integer`: No description
- **description** `string`: No description
- **quantity** `number`: No description
- **unit** `string`: No description
- **unit_price** `number`: No description
- **discount_percentage** `number`: No description
- **tax_type** `string`: No description
- **vat_rate** `number`: No description
- **regime_key** `string`: No description
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
---
# List recurring invoices API Reference
Lists all recurring invoices for the authenticated user with filters and pagination.
## GET /v1/recurring-invoices
**List recurring invoices**
Lists all recurring invoices for the authenticated user with filters and pagination.
### Parameters
- **status** (optional) in query: No description
- **customer_id** (optional) in query: No description
- **undefined** (optional): No description
- **undefined** (optional): No description
- **sortBy** (optional) in query: No description
- **sortOrder** (optional) in query: No description
### Responses
#### 200: Recurring invoices list retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `array[RecurringInvoiceResponse]`:
- **pagination** `object`:
- **current_page** (required) `integer`: No description (example: 1)
- **total_pages** (required) `integer`: No description (example: 5)
- **total_items** (required) `integer`: No description (example: 87)
- **items_per_page** (required) `integer`: No description (example: 20)
- **has_next** `boolean`: No description
- **has_previous** `boolean`: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## RecurringInvoiceResponse
### Properties
- **id** `string`: No description
- **name** `string`: No description
- **frequency** `string`: No description - one of: MONTHLY
- **day_of_month** `integer`: No description
- **start_date** `string`: No description
- **end_date** `string`: No description
- **next_generation** `string`: No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission.
- **status** `string`: No description - one of: ACTIVE, PAUSED, COMPLETED
- **series_id** `string`: No description
- **series_code** `string`: No description
- **invoice_type** `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string`: No description
- **recipient_fiscal_name** `string`: No description
- **recipient_nif** `string`: No description
- **lines** `array`: No description
- **payment_method** `string`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration**: No description
- **generated_invoices** `integer`: No description
- **last_generation** `string`: No description
- **source_invoice_id** `string`: No description
- **created_at** `string`: No description
- **updated_at** `string`: No description
---
# Pause a recurring invoice API Reference
Pauses automatic invoice generation. The recurring invoice can be resumed later without losing its schedule configuration.
## POST /v1/recurring-invoices/{recurring_invoice_id}/pause
**Pause a recurring invoice**
Pauses automatic invoice generation. The recurring invoice can be resumed later without losing its schedule configuration.
### Parameters
- **recurring_invoice_id** (required) in path: No description
### Responses
#### 200: Recurring invoice paused successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **frequency** `string`: No description - one of: MONTHLY
- **day_of_month** `integer`: No description
- **start_date** `string` (date): No description
- **end_date** `string` (date): No description
- **next_generation** `string` (date): No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission. (example: 3)
- **status** `string`: No description - one of: ACTIVE, PAUSED, COMPLETED
- **series_id** `string` (uuid): No description
- **series_code** `string`: No description
- **invoice_type** `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string` (uuid): No description
- **recipient_fiscal_name** `string`: No description
- **recipient_nif** `string`: No description
- **lines** `array[InvoiceLineTemplateResponse]`:
- **payment_method** `string`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration** `object`:
- **recipients** `array[string]`:
- **cc** `array[string]`:
- **subject** `string`: No description
- **message** `string`: No description
- **generated_invoices** `integer`: No description
- **last_generation** `string` (date-time): No description
- **source_invoice_id** `string` (uuid): No description
- **created_at** `string` (date-time): No description
- **updated_at** `string` (date-time): No description
#### 400: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLineTemplateResponse
### Properties
- **id** `string`: No description
- **order** `integer`: No description
- **description** `string`: No description
- **quantity** `number`: No description
- **unit** `string`: No description
- **unit_price** `number`: No description
- **discount_percentage** `number`: No description
- **tax_type** `string`: No description
- **vat_rate** `number`: No description
- **regime_key** `string`: No description
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
---
# Preview next invoice from recurring template API Reference
Returns a computed preview of what the next invoice would look like when
generated from this recurring template. Uses current issuer, recipient,
and series data. Nothing is persisted.
## GET /v1/recurring-invoices/{recurring_invoice_id}/preview
**Preview next invoice from recurring template**
Returns a computed preview of what the next invoice would look like when
generated from this recurring template. Uses current issuer, recipient,
and series data. Nothing is persisted.
### Parameters
- **recurring_invoice_id** (required) in path: UUID of the recurring invoice template
### Responses
#### 200: Invoice preview computed successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** (required) `string` (uuid): Unique invoice UUID (example: "550e8400-e29b-41d4-a716-446655440000")
- **invoice_number** `string`: Complete invoice number (series + sequential).
**Null for draft invoices** — assigned automatically when issued.
(example: "2025/0001")
- **series** (required) `object`:
- **id** (required) `string` (uuid): Invoice series UUID (example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890")
- **code** (required) `string`: Alphanumeric series code (example: "FAC")
- **number** `integer`: Sequential number within the series.
**Null for draft invoices** — assigned automatically when issued.
(example: 1)
- **type** (required) `string`: - STANDARD: Standard invoice
- CORRECTIVE: Corrects or cancels a previous invoice
- SIMPLIFIED: Simplified invoice without all requirements (up to 400€)
- **status** (required) `string`: - SCHEDULED: Scheduled invoice to be issued automatically on a future date
- DRAFT: Draft invoice not sent yet (modifiable)
- ISSUED: Finalized invoice with definitive number but not sent
- SENT: Invoice sent to customer
- PAID: Invoice paid
- OVERDUE: Overdue invoice (not paid after due date)
- RECTIFIED: Partially corrected invoice (one or more PARTIAL corrective invoices)
- VOIDED: Completely cancelled invoice (TOTAL corrective invoice)
- **issue_date** (required) `string` (date): Invoice issue date (example: "2025-01-15")
- **due_date** `string` (date): Payment due date (must be the same as or after `issue_date`) (example: "2025-02-14")
- **payment_date** `string` (date): Business date when the payment was received (e.g., the date on the bank statement).
Set by the user when marking the invoice as paid. Only present when status is PAID.
Contrast with `paid_at`, which is the system timestamp of when the status change was recorded.
(example: "2025-01-20")
- **sent_at** `string` (date-time): System timestamp when the invoice was marked as sent.
Present when status is SENT or later.
(example: "2025-01-29T18:45:00Z")
- **paid_at** `string` (date-time): System timestamp when the payment was recorded in the system.
Automatically set when the invoice status changes to PAID.
Contrast with `payment_date`, which is the business date chosen by the user.
(example: "2025-02-05T10:30:00Z")
- **auto_emit_after** `string` (date): Date when this draft will be auto-emitted if not manually issued.
Only present for drafts created from recurring invoices with preview_days > 0.
(example: "2025-03-20")
- **scheduled_for** `string` (date): Date when the invoice should be automatically processed.
Only present when status is SCHEDULED.
(example: "2025-02-15")
- **scheduled_action** `string`: Action to perform when processing a scheduled invoice:
- DRAFT: Create as draft for manual review
- ISSUE_AND_SEND: Issue and send automatically via email
- **issuer** (required) `object`:
- **legal_name** (required) `string`: Issuer legal name (example: "Juan Pérez García")
- **trade_name** `string`: Issuer trade name (optional) (example: "JP Web Development")
- **nif** (required) `string`: Spanish Tax ID (9 alphanumeric characters).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **address** (required) `object`:
- **street** (required) `string`: Full address (street, number, floor, etc.) - Latin characters only (example: "Calle Mayor, 123")
- **number** (required) `string`: Street number (example: "123")
- **floor** `string`: Floor or level (example: "2º A")
- **door** `string`: Door or apartment (example: "A")
- **postal_code** (required) `string`: Postal code (5 digits for Spain, free format for other countries) (example: "28001")
- **city** (required) `string`: City or town - Latin characters only (example: "Madrid")
- **province** (required) `string`: Province or state - Latin characters only (example: "Madrid")
- **country** (required) `string`: Country - Latin characters only (example: "España")
- **country_code** `string`: ISO 3166-1 alpha-2 country code (example: "ES")
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **web** `string`: Issuer website (optional) (example: "https://beel.es")
- **logo_url** `string`: Issuer logo URL (optional)
- **additional_info** `string`: Additional issuer information (collegiate number, professional registration, etc.)
(example: "Nº Colegiado: 12345")
- **recipient** (required) `object`: Recipient data in the invoice response.
Note: For simplified invoices, only legal_name may be present.
NIF and address are optional for SIMPLIFIED type invoices.
- **customer_id** `string` (uuid): Customer UUID in the system (optional)
- **legal_name** (required) `string`: Recipient legal name (example: "Empresa SL")
- **trade_name** `string`: Recipient trade name (optional) (example: "Empresa")
- **nif** `string`: Spanish Tax ID (9 alphanumeric characters).
Optional for simplified invoices (SIMPLIFIED type).
Valid formats:
- DNI: 8 digits + letter (e.g., 12345678A)
- NIE: X/Y/Z + 7 digits + letter (e.g., X1234567A)
- CIF: Letter + 7 digits + digit/letter (e.g., B12345678)
(example: "12345678A")
- **alternative_id**: No description
- **address**: Address (optional for simplified invoices)
- **phone** `string`: Phone number. Allows digits, spaces, dashes, parentheses, and optional leading +
- **email** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **lines** (required) `array[InvoiceLine]`:
- **totals** (required) `object`:
- **taxable_base** (required) `number`: Total taxable base (can be negative in corrective invoices) (example: 2000)
- **total_discounts** `number`: No description (example: 0)
- **vat_breakdown** `array[object]`:
- **type** (required) `number`: No description (example: 21)
- **base** (required) `number`: No description (example: 2000)
- **amount** (required) `number`: No description (example: 420)
- **total_vat** (required) `number`: Total VAT (can be negative in corrective invoices) (example: 420)
- **surcharge_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_equivalence_surcharge** (required) `number`: Total equivalence surcharge (can be negative in corrective invoices) (example: 0)
- **irpf_breakdown** `array[object]`:
- **type** (required) `number`: No description
- **base** (required) `number`: No description
- **amount** (required) `number`: No description
- **total_irpf** (required) `number`: Total personal income tax withheld (can be negative in corrective invoices) (example: 300)
- **invoice_total** (required) `number`: Total amount to pay (base + VAT + RE - IRPF, can be negative in corrective invoices) (example: 2120)
- **payment_info** `object`:
- **method**: Preferred payment method.
If NONE is selected, no payment information will be shown on the invoice.
- **iban** `string`: IBAN (International Bank Account Number).
Required when payment method is BANK_TRANSFER.
- **swift** `string`: SWIFT/BIC code
- **payment_term_days** `integer`: Payment term in days (optional, default 30) (example: 30)
- **notes** `string`: Additional observations or notes
- **rectified_invoice_id** `string` (uuid): UUID of the invoice being rectified (only for corrective invoices)
- **rectification_reason** `string`: Reason for rectification (only for corrective invoices)
- **recurring_invoice_id** `string` (uuid): UUID of the recurring invoice that generated this invoice (if any)
- **recurring_invoice_name** `string`: Name of the recurring invoice (denormalized for display)
- **rectification_type** `string`: Type of rectification applied to a corrective invoice:
- TOTAL: Completely cancels the original invoice (status → VOIDED)
- PARTIAL: Partially corrects the original invoice (status → RECTIFIED)
- **rectification_code** `string`: Rectification codes according to VeriFactu regulations (AEAT):
- R1: Error founded in law and Art. 80 One, Two and Six LIVA
- R2: Article 80 Three LIVA (Bankruptcy proceedings)
- R3: Article 80 Four LIVA (Uncollectable debts)
- R4: Other causes
- R5: Simplified invoices (Art. 80 One and Two LIVA) - ONLY for simplified invoices
- **metadata** `object`: Additional metadata in key-value format. Useful examples:
- stripe_payment_id: Stripe payment ID
- stripe_charge_id: Stripe charge ID
- external_order_id: External order ID
- payment_platform: Payment platform used
- internal_notes: Internal notes not visible to customer
(example: {"stripe_payment_id":"pi_3NqFGb2eZvKYlo2C0z1234AB","stripe_charge_id":"ch_3NqFGb2eZvKYlo2C1234CDEF","external_order_id":"ORD-2025-0042","payment_platform":"stripe"})
- **pdf_download_url** `string`: Relative URL to download the PDF via the API endpoint.
Path is relative to the API base URL (e.g., https://api.beel.es/api).
Only present when the invoice has a generated PDF.
(example: "/v1/invoices/550e8400-e29b-41d4-a716-446655440000/pdf")
- **verifactu** `object`: VeriFactu compliance information (optional).
Some self-employed workers may be required to use this AEAT system,
while others may choose not to.
- **enabled** `boolean`: Whether VeriFactu is enabled for this invoice
- **invoice_hash** `string`: Invoice SHA-256 hash according to VeriFactu regulations (example: "3A5B7C9D1E2F3A4B5C6D7E8F9A0B1C2D3E4F5A6B7C8D9E0F1A2B3C4D5E6F7A8B")
- **chaining_hash** `string`: Chaining hash with previous invoice (example: "7F8E9D0C1B2A3F4E5D6C7B8A9F0E1D2C3B4A5F6E7D8C9B0A1F2E3D4C5B6A7F8")
- **registration_number** `string`: Registration number in the VeriFactu system (example: "VERIFACTU2025000001")
- **qr_url** `string`: QR code URL for verification (example: "https://verifactu.agenciatributaria.gob.es/v?id=ABC123XYZ")
- **qr_base64** `string`: QR code as base64-encoded PNG for embedding in custom PDFs.
Only present when submission_status = ACCEPTED.
(example: "iVBORw0KGgoAAAANSUhEUgAAAMgAAADI...")
- **registration_date** `string` (date-time): VeriFactu registration date and time
- **submission_status** `string`: Submission status to AEAT - one of: PENDING, SENT, ACCEPTED, VOIDED, REJECTED
- **error_code** `string`: Error code returned by AEAT. Present when submission_status is REJECTED. (example: "3000")
- **error_message** `string`: Human-readable error description returned by AEAT. Present when submission_status is REJECTED. (example: "Factura ya existe en el sistema")
- **attachments** `array[object]`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **url** `string`: No description
- **type** `string`: No description
- **sending_history** `array[object]`:
- **id** `string` (uuid): No description
- **date** `string` (date-time): No description
- **recipient** `string`: Email address (minimum valid email is 5 chars, e.g. a@b.co)
- **status** `string`: No description - one of: SENT, FAILED
- **error** `string`: No description
- **created_at** (required) `string` (date-time): No description
- **updated_at** (required) `string` (date-time): No description
- **deleted_at** `string` (date-time): No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLine
### Properties
- **description** (required) `string`: Description of the invoiced concept (max: 500)
- **quantity** (required) `number`: Product/service quantity (can be negative in corrective invoices)
- **unit** `string`: No description (default: hours)
- **unit_price** (required) `number`: Unit price before taxes.
Supports up to 4 decimal places for micro-pricing (e.g., €0.0897/unit for labels, packaging).
Final amounts are always rounded to 2 decimals.
(min: 0) (max: 999999.9999)
- **discount_percentage** `number`: Discount percentage applied (0-100) (default: 0) (min: 0) (max: 100)
- **main_tax**: No description
- **equivalence_surcharge_rate**: No description
- **irpf_rate**: No description
- **taxable_base** `number`: Line taxable base (after discount, can be negative in corrective invoices)
- **line_total** (required) `number`: Line total with taxes (can be negative in corrective invoices)
---
# Resume a paused recurring invoice API Reference
Resumes automatic invoice generation for a previously paused recurring invoice. The next generation date is recalculated from the current date.
## POST /v1/recurring-invoices/{recurring_invoice_id}/resume
**Resume a paused recurring invoice**
Resumes automatic invoice generation for a previously paused recurring invoice. The next generation date is recalculated from the current date.
### Parameters
- **recurring_invoice_id** (required) in path: No description
### Responses
#### 200: Recurring invoice resumed successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **frequency** `string`: No description - one of: MONTHLY
- **day_of_month** `integer`: No description
- **start_date** `string` (date): No description
- **end_date** `string` (date): No description
- **next_generation** `string` (date): No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission. (example: 3)
- **status** `string`: No description - one of: ACTIVE, PAUSED, COMPLETED
- **series_id** `string` (uuid): No description
- **series_code** `string`: No description
- **invoice_type** `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string` (uuid): No description
- **recipient_fiscal_name** `string`: No description
- **recipient_nif** `string`: No description
- **lines** `array[InvoiceLineTemplateResponse]`:
- **payment_method** `string`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration** `object`:
- **recipients** `array[string]`:
- **cc** `array[string]`:
- **subject** `string`: No description
- **message** `string`: No description
- **generated_invoices** `integer`: No description
- **last_generation** `string` (date-time): No description
- **source_invoice_id** `string` (uuid): No description
- **created_at** `string` (date-time): No description
- **updated_at** `string` (date-time): No description
#### 400: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLineTemplateResponse
### Properties
- **id** `string`: No description
- **order** `integer`: No description
- **description** `string`: No description
- **quantity** `number`: No description
- **unit** `string`: No description
- **unit_price** `number`: No description
- **discount_percentage** `number`: No description
- **tax_type** `string`: No description
- **vat_rate** `number`: No description
- **regime_key** `string`: No description
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
---
# Skip the next generation API Reference
Skips the next scheduled invoice generation and advances the generation date to the following period.
## POST /v1/recurring-invoices/{recurring_invoice_id}/skip
**Skip the next generation**
Skips the next scheduled invoice generation and advances the generation date to the following period.
### Parameters
- **recurring_invoice_id** (required) in path: No description
### Responses
#### 200: Next generation skipped successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **frequency** `string`: No description - one of: MONTHLY
- **day_of_month** `integer`: No description
- **start_date** `string` (date): No description
- **end_date** `string` (date): No description
- **next_generation** `string` (date): No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission. (example: 3)
- **status** `string`: No description - one of: ACTIVE, PAUSED, COMPLETED
- **series_id** `string` (uuid): No description
- **series_code** `string`: No description
- **invoice_type** `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string` (uuid): No description
- **recipient_fiscal_name** `string`: No description
- **recipient_nif** `string`: No description
- **lines** `array[InvoiceLineTemplateResponse]`:
- **payment_method** `string`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration** `object`:
- **recipients** `array[string]`:
- **cc** `array[string]`:
- **subject** `string`: No description
- **message** `string`: No description
- **generated_invoices** `integer`: No description
- **last_generation** `string` (date-time): No description
- **source_invoice_id** `string` (uuid): No description
- **created_at** `string` (date-time): No description
- **updated_at** `string` (date-time): No description
#### 400: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## InvoiceLineTemplateResponse
### Properties
- **id** `string`: No description
- **order** `integer`: No description
- **description** `string`: No description
- **quantity** `number`: No description
- **unit** `string`: No description
- **unit_price** `number`: No description
- **discount_percentage** `number`: No description
- **tax_type** `string`: No description
- **vat_rate** `number`: No description
- **regime_key** `string`: No description
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
---
# Update a recurring invoice API Reference
Updates the schedule, template lines, or recipient of a recurring invoice. Only allowed while the invoice is active or paused.
## PUT /v1/recurring-invoices/{recurring_invoice_id}
**Update a recurring invoice**
Updates the schedule, template lines, or recipient of a recurring invoice. Only allowed while the invoice is active or paused.
### Parameters
- **recurring_invoice_id** (required) in path: No description
### Request Body
- **name** `string`: No description
- **day_of_month** `integer`: No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission.
- **end_date** `string` (date): No description
- **series_id** `string` (uuid): No description
- **customer_id** `string` (uuid): No description
- **lines** `array[RecurringLineRequest]`:
- **payment_method**: No description
- **payment_iban** `string`: No description
- **payment_swift** `string`: No description
- **payment_term_days** `integer`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration**: No description
### Responses
#### 200: Recurring invoice updated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **name** `string`: No description
- **frequency** `string`: No description - one of: MONTHLY
- **day_of_month** `integer`: No description
- **start_date** `string` (date): No description
- **end_date** `string` (date): No description
- **next_generation** `string` (date): No description
- **preview_days** `integer`: Days before emission date to create a draft for review. 0 means immediate emission. (example: 3)
- **status** `string`: No description - one of: ACTIVE, PAUSED, COMPLETED
- **series_id** `string` (uuid): No description
- **series_code** `string`: No description
- **invoice_type** `string`: No description - one of: STANDARD, SIMPLIFIED
- **customer_id** `string` (uuid): No description
- **recipient_fiscal_name** `string`: No description
- **recipient_nif** `string`: No description
- **lines** `array[InvoiceLineTemplateResponse]`:
- **payment_method** `string`: No description
- **notes** `string`: No description
- **verifactu_enabled** `boolean`: No description
- **send_automatically** `boolean`: No description
- **email_configuration** `object`:
- **recipients** `array[string]`:
- **cc** `array[string]`:
- **subject** `string`: No description
- **message** `string`: No description
- **generated_invoices** `integer`: No description
- **last_generation** `string` (date-time): No description
- **source_invoice_id** `string` (uuid): No description
- **created_at** `string` (date-time): No description
- **updated_at** `string` (date-time): No description
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## RecurringLineRequest
### Properties
- **description** (required) `string`: No description (max: 500)
- **quantity** (required) `number`: No description (min: 0.01)
- **unit** `string`: No description (max: 20)
- **unit_price** (required) `number`: No description (min: 0)
- **discount_percentage** `number`: No description (min: 0) (max: 100)
- **tax_type** `string`: No description (default: IVA)
- **vat_rate** (required) `number`: No description
- **regime_key** `string`: No description (default: 01)
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
## InvoiceLineTemplateResponse
### Properties
- **id** `string`: No description
- **order** `integer`: No description
- **description** `string`: No description
- **quantity** `number`: No description
- **unit** `string`: No description
- **unit_price** `number`: No description
- **discount_percentage** `number`: No description
- **tax_type** `string`: No description
- **vat_rate** `number`: No description
- **regime_key** `string`: No description
- **equivalence_surcharge_rate** `number`: No description
- **irpf_rate** `number`: No description
---
# Get user tax configuration API Reference
Retrieves the user's tax configuration, including:
- Default tax regime (VAT, IGIC, IPSI, OTHERS)
- Default main tax percentage
- IRPF and equivalence surcharge configuration
## GET /v1/configuration/taxes
**Get user tax configuration**
Retrieves the user's tax configuration, including:
- Default tax regime (VAT, IGIC, IPSI, OTHERS)
- Default main tax percentage
- IRPF and equivalence surcharge configuration
### Responses
#### 200: Configuration retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **default_main_tax** (required): No description
- **apply_equivalence_surcharge** (required) `boolean`: Whether the freelancer is under the equivalence surcharge regime.
**Business rule**: If `true`, the `default_equivalence_surcharge` field is REQUIRED.
- **default_equivalence_surcharge**: Default equivalence surcharge.
**Business rule**: REQUIRED if `apply_equivalence_surcharge` is `true`.
- **apply_irpf** (required) `boolean`: Whether IRPF withholding should be applied to invoices.
**Business rule**: If `true` and `irpf_exempt` is `false`,
the `default_irpf_rate` field is REQUIRED.
- **default_irpf_rate**: Default IRPF for new invoices.
**Business rule**: REQUIRED if `apply_irpf` is `true` and `irpf_exempt` is `false`.
- **irpf_exempt** `boolean`: Whether the freelancer is exempt from IRPF withholding (e.g., business start).
**Note**: When `true`, any provided `default_irpf_rate` is saved but not applied to invoices.
This allows pre-configuring the rate for when the exemption ends.
- **default_payment_method**: Default payment method for new invoices.
If NONE is selected, no payment information will be shown on the invoice.
- **payment_term_days** `integer`: Default payment term in days (0-365). Null means no default term.
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get complete tax types catalog API Reference
Retrieves the complete catalog of available tax types with structured information
for tax configuration in Spain:
- **Tax regimes**: VAT (Peninsula), IGIC (Canary Islands), IPSI (Ceuta/Melilla), OTHERS
- **Percentages per regime**: Valid percentages for each tax type
- **Regime codes**: VeriFactu codes for each tax type
- **IRPF**: Available withholding percentages
- **Equivalence surcharge**: Automatic mappings based on VAT percentage
- **Utilities**: Validation functions and geographic auto-detection
This endpoint provides all necessary information for the frontend
without duplicating tax validation logic.
## GET /v1/configuration/tax-types
**Get complete tax types catalog**
Retrieves the complete catalog of available tax types with structured information
for tax configuration in Spain:
- **Tax regimes**: VAT (Peninsula), IGIC (Canary Islands), IPSI (Ceuta/Melilla), OTHERS
- **Percentages per regime**: Valid percentages for each tax type
- **Regime codes**: VeriFactu codes for each tax type
- **IRPF**: Available withholding percentages
- **Equivalence surcharge**: Automatic mappings based on VAT percentage
- **Utilities**: Validation functions and geographic auto-detection
This endpoint provides all necessary information for the frontend
without duplicating tax validation logic.
### Responses
#### 200: Catalog retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **tax_regimes** `array[TaxRegime]`:
- **irpf_types** `array[IrpfType]`:
- **equivalence_surcharges** `array[EquivalenceSurcharge]`:
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## TaxRegime
### Properties
- **code** (required) `string`: Tax regime code - one of: IVA, IGIC, IPSI, OTHER
- **name** (required) `string`: Tax regime name
- **description** (required) `string`: Detailed description of the tax regime
- **tax_rates** (required) `array`: Available percentages in this regime
- **applies_equivalence_surcharge** (required) `boolean`: Whether this regime applies equivalence surcharge
- **regime_keys** (required) `array`: Valid VeriFactu regime keys for this tax type
## IrpfType
### Properties
- **percentage** (required) `number`: IRPF withholding percentage
- **description** (required) `string`: IRPF type description
- **active** (required) `boolean`: Whether the IRPF type is active (default: true)
## EquivalenceSurcharge
### Properties
- **percentage** (required) `number`: Equivalence surcharge percentage
- **associated_vat** (required) `number`: VAT percentage to which this surcharge is associated
- **description** (required) `string`: Equivalence surcharge description
- **active** (required) `boolean`: Whether the surcharge is active (default: true)
---
# Update tax configuration API Reference
Updates the user's tax configuration
## PUT /v1/configuration/taxes
**Update tax configuration**
Updates the user's tax configuration
### Request Body
- **default_main_tax**: Default main tax configuration.
If provided, completely replaces the current configuration.
- **apply_equivalence_surcharge** `boolean`: Whether the freelancer is under the equivalence surcharge regime
- **default_equivalence_surcharge**: No description
- **apply_irpf** `boolean`: Whether IRPF withholding should be applied
- **default_irpf_rate**: No description
- **irpf_exempt** `boolean`: Whether the freelancer is exempt from IRPF withholding
- **default_payment_method** `string`: Default payment method for new invoices.
If NONE is selected, no payment information will be shown on the invoice.
- **payment_term_days** `integer`: Default payment term in days (0-365)
### Responses
#### 200: Configuration updated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **default_main_tax** (required): No description
- **apply_equivalence_surcharge** (required) `boolean`: Whether the freelancer is under the equivalence surcharge regime.
**Business rule**: If `true`, the `default_equivalence_surcharge` field is REQUIRED.
- **default_equivalence_surcharge**: Default equivalence surcharge.
**Business rule**: REQUIRED if `apply_equivalence_surcharge` is `true`.
- **apply_irpf** (required) `boolean`: Whether IRPF withholding should be applied to invoices.
**Business rule**: If `true` and `irpf_exempt` is `false`,
the `default_irpf_rate` field is REQUIRED.
- **default_irpf_rate**: Default IRPF for new invoices.
**Business rule**: REQUIRED if `apply_irpf` is `true` and `irpf_exempt` is `false`.
- **irpf_exempt** `boolean`: Whether the freelancer is exempt from IRPF withholding (e.g., business start).
**Note**: When `true`, any provided `default_irpf_rate` is saved but not applied to invoices.
This allows pre-configuring the rate for when the exemption ends.
- **default_payment_method**: Default payment method for new invoices.
If NONE is selected, no payment information will be shown on the invoice.
- **payment_term_days** `integer`: Default payment term in days (0-365). Null means no default term.
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Get VeriFactu configuration API Reference
Retrieves the current VeriFactu configuration
## GET /v1/configuration/verifactu
**Get VeriFactu configuration**
Retrieves the current VeriFactu configuration
### Responses
#### 200: Configuration retrieved successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **enabled** (required) `boolean`: Whether VeriFactu is enabled for this user.
When enabled, the user can submit invoices to AEAT.
Freelancers who don't need to submit invoices to AEAT can leave it disabled.
- **apply_by_default** (required) `boolean`: Whether VeriFactu should be automatically applied to new invoices.
Requires 'enabled' to be true.
- **nif_status** `string`: VeriFactu registration status (can be null if VeriFactu was never enabled):
- PENDING: Initial registration in progress
- ACTIVATED: NIF validated and user created in the corresponding environment
- DEACTIVATED: Deactivated (data retained for 30 days)
- ERROR: Some step of the process failed
- one of: PENDING, ACTIVATED, DEACTIVATED, ERROR
- **nif_registered_at** `string` (date-time): Successful activation date in VeriFactu production
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Update VeriFactu configuration API Reference
Updates the user's VeriFactu configuration.
**Business rules:**
- If `enabled` is false, `apply_by_default` must also be false
- If `apply_by_default` is true, `enabled` must be true
## PUT /v1/configuration/verifactu
**Update VeriFactu configuration**
Updates the user's VeriFactu configuration.
**Business rules:**
- If `enabled` is false, `apply_by_default` must also be false
- If `apply_by_default` is true, `enabled` must be true
### Request Body
- **enabled** (required) `boolean`: Whether VeriFactu is enabled for this user.
When enabled, the user can submit invoices to AEAT.
Freelancers who don't need to submit invoices to AEAT can leave it disabled.
- **apply_by_default** (required) `boolean`: Whether VeriFactu should be automatically applied to new invoices.
Requires 'enabled' to be true.
- **nif_status** `string`: VeriFactu registration status (can be null if VeriFactu was never enabled):
- PENDING: Initial registration in progress
- ACTIVATED: NIF validated and user created in the corresponding environment
- DEACTIVATED: Deactivated (data retained for 30 days)
- ERROR: Some step of the process failed
- one of: PENDING, ACTIVATED, DEACTIVATED, ERROR
- **nif_registered_at** `string` (date-time): Successful activation date in VeriFactu production
### Responses
#### 200: Configuration updated successfully
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **enabled** (required) `boolean`: Whether VeriFactu is enabled for this user.
When enabled, the user can submit invoices to AEAT.
Freelancers who don't need to submit invoices to AEAT can leave it disabled.
- **apply_by_default** (required) `boolean`: Whether VeriFactu should be automatically applied to new invoices.
Requires 'enabled' to be true.
- **nif_status** `string`: VeriFactu registration status (can be null if VeriFactu was never enabled):
- PENDING: Initial registration in progress
- ACTIVATED: NIF validated and user created in the corresponding environment
- DEACTIVATED: Deactivated (data retained for 30 days)
- ERROR: Some step of the process failed
- one of: PENDING, ACTIVATED, DEACTIVATED, ERROR
- **nif_registered_at** `string` (date-time): Successful activation date in VeriFactu production
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 500: Internal server error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Create webhook subscription API Reference
Register an HTTPS endpoint to receive real-time event notifications. Every delivery is signed with BeeL-Signature (HMAC-SHA256). The secret is returned once on creation — store it securely. Maximum 10 active webhook subscriptions per account.
## POST /v1/webhooks
**Create webhook subscription**
Register an HTTPS endpoint to receive real-time event notifications. Every delivery is signed with BeeL-Signature (HMAC-SHA256). The secret is returned once on creation — store it securely. Maximum 10 active webhook subscriptions per account.
### Request Body
- **url** (required) `string` (uri): HTTPS endpoint URL that will receive webhook POST requests.
- **events** (required) `array[WebhookEventTypeEnum]`: List of event types to subscribe to.
### Responses
#### 201: Webhook subscription created
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## WebhookEventTypeEnum
Available webhook event types:
- `invoice.emitted` — Invoice emitted and finalized
- `invoice.email.sent` — Invoice sent by email
- `invoice.cancelled` — Invoice cancelled
- `verifactu.status.updated` — VeriFactu status changed (PENDING, ACCEPTED, REJECTED)
---
# Delete webhook subscription API Reference
Permanently deletes a webhook subscription. No further events will be delivered.
## DELETE /v1/webhooks/{webhook_id}
**Delete webhook subscription**
Permanently deletes a webhook subscription. No further events will be delivered.
### Parameters
- **webhook_id** (required) in path: No description
### Responses
#### 204: Subscription deleted
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# List webhook delivery logs API Reference
Returns the last 50 delivery attempts for a webhook subscription.
## GET /v1/webhooks/{webhook_id}/deliveries
**List webhook delivery logs**
Returns the last 50 delivery attempts for a webhook subscription.
### Parameters
- **webhook_id** (required) in path: No description
### Responses
#### 200: List of delivery logs
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `array[WebhookDeliveryLog]`:
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## WebhookDeliveryLog
### Properties
- **id** `string`: No description
- **subscription_id** `string`: No description
- **webhook_event_id** `string`: Groups all delivery attempts for the same logical event.
- **event_type** `string`: No description
- **attempt_number** `integer`: Delivery attempt number (1 = first, 2 = first retry, etc.)
- **http_status** `integer`: HTTP response status code. Null if connection failed.
- **response_body** `string`: No description
- **duration_ms** `integer`: Delivery duration in milliseconds.
- **success** `boolean`: No description
- **error_message** `string`: Error description for failed deliveries (timeout, connection error, etc.)
- **payload** `string`: The JSON payload that was sent (or attempted) to your endpoint.
- **request_headers** `object`: HTTP headers sent to your endpoint with this delivery attempt.
Includes `BeeL-Signature`, `BeeL-Event`, `BeeL-Event-Id`, `BeeL-Delivery-Id`, and `Idempotency-Key`.
- **delivered_at** `string`: No description
---
# List webhook subscriptions API Reference
Returns all webhook subscriptions for the authenticated account.
## GET /v1/webhooks
**List webhook subscriptions**
Returns all webhook subscriptions for the authenticated account.
### Parameters
- **undefined** (optional): No description
- **undefined** (optional): No description
### Responses
#### 200: List of webhook subscriptions
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **webhooks** `array[WebhookSubscription]`:
- **pagination** `object`:
- **current_page** (required) `integer`: No description (example: 1)
- **total_pages** (required) `integer`: No description (example: 5)
- **total_items** (required) `integer`: No description (example: 87)
- **items_per_page** (required) `integer`: No description (example: 20)
- **has_next** `boolean`: No description
- **has_previous** `boolean`: No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## WebhookSubscription
### Properties
- **id** `string`: No description
- **url** `string`: No description
- **events** `array`: No description
- **active** `boolean`: No description
- **last_used_at** `string`: No description
- **created_at** `string`: No description
---
# Retry a failed webhook delivery API Reference
Immediately retries a webhook delivery using the original payload.
Creates a new delivery log entry with the result.
## POST /v1/webhooks/{webhook_id}/deliveries/{delivery_id}/retry
**Retry a failed webhook delivery**
Immediately retries a webhook delivery using the original payload.
Creates a new delivery log entry with the result.
### Parameters
- **webhook_id** (required) in path: No description
- **delivery_id** (required) in path: No description
### Responses
#### 200: Retry result
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **subscription_id** `string` (uuid): No description
- **webhook_event_id** `string` (uuid): Groups all delivery attempts for the same logical event.
- **event_type** `string`: No description (example: "verifactu.status.updated")
- **attempt_number** `integer`: Delivery attempt number (1 = first, 2 = first retry, etc.)
- **http_status** `integer`: HTTP response status code. Null if connection failed. (example: 200)
- **response_body** `string`: No description
- **duration_ms** `integer`: Delivery duration in milliseconds.
- **success** `boolean`: No description
- **error_message** `string`: Error description for failed deliveries (timeout, connection error, etc.)
- **payload** `string`: The JSON payload that was sent (or attempted) to your endpoint.
- **request_headers** `object`: HTTP headers sent to your endpoint with this delivery attempt.
Includes `BeeL-Signature`, `BeeL-Event`, `BeeL-Event-Id`, `BeeL-Delivery-Id`, and `Idempotency-Key`.
(example: {"BeeL-Signature":"t=1741362026,v1=3c4f7a2e1b9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f","BeeL-Event":"verifactu.status.updated","BeeL-Event-Id":"8ee6b023-c4e5-482e-93ca-dc66da2f9cb5","BeeL-Delivery-Id":"b3873959-67d8-4a11-87ba-b39cc2d395fe","Idempotency-Key":"8ee6b023-c4e5-482e-93ca-dc66da2f9cb5"})
- **delivered_at** `string` (date-time): No description
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Rotate webhook secret API Reference
Generates a new HMAC secret for a webhook subscription.
The old secret is **immediately invalidated** — update your signature verification
logic before rotating to avoid missing events during the transition.
The new secret is only returned **once** in this response.
## POST /v1/webhooks/{webhook_id}/secret
**Rotate webhook secret**
Generates a new HMAC secret for a webhook subscription.
The old secret is **immediately invalidated** — update your signature verification
logic before rotating to avoid missing events during the transition.
The new secret is only returned **once** in this response.
### Parameters
- **webhook_id** (required) in path: No description
### Responses
#### 200: Secret rotated — new secret returned (only shown once)
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
---
# Update webhook subscription API Reference
Partially updates a webhook subscription. Only provided fields are updated.
Use this endpoint to:
- **Change the endpoint URL** (`url`)
- **Change subscribed events** (`events`)
- **Enable or disable** the subscription (`active`)
## PATCH /v1/webhooks/{webhook_id}
**Update webhook subscription**
Partially updates a webhook subscription. Only provided fields are updated.
Use this endpoint to:
- **Change the endpoint URL** (`url`)
- **Change subscribed events** (`events`)
- **Enable or disable** the subscription (`active`)
### Parameters
- **webhook_id** (required) in path: No description
### Request Body
- **url** `string` (uri): New HTTPS endpoint URL.
- **events** `array[WebhookEventTypeEnum]`: New list of event types to subscribe to.
- **active** `boolean`: Enable or disable the webhook subscription.
### Responses
#### 200: Webhook subscription updated
**Response Body:**
- **success** (required) `boolean`: No description (example: true)
- **data** (required): Response data (type varies by endpoint - can be object or array)
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
- **data** `object`:
- **id** `string` (uuid): No description
- **url** `string` (uri): No description
- **events** `array[string]`:
- **active** `boolean`: No description
- **last_used_at** `string` (date-time): No description
- **created_at** `string` (date-time): No description
#### 400: Bad request
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 401: Missing or invalid authentication
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 404: Resource not found
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
#### 422: Validation error
**Response Body:**
- **success** (required) `boolean`: No description (example: false)
- **error** (required) `object`:
- **code** (required) `string`: No description (example: "VALIDATION_ERROR")
- **message** (required) `string`: No description (example: "The provided data is not valid")
- **details** `object`: No description (example: {"field":"specific error message"})
- **meta** `object`:
- **timestamp** `string` (date-time): No description (example: "2025-01-15T10:30:00Z")
- **request_id** `string`: No description (example: "4bf92f3577b34da6a3ce929d0e0e4736")
---
# Related Schema Definitions
## WebhookEventTypeEnum
Available webhook event types:
- `invoice.emitted` — Invoice emitted and finalized
- `invoice.email.sent` — Invoice sent by email
- `invoice.cancelled` — Invoice cancelled
- `verifactu.status.updated` — VeriFactu status changed (PENDING, ACCEPTED, REJECTED)
---