Every call carries an X-Api-Key header
factura.com.do does not use Bearer or OAuth for machine-to-machine integrations. An application key travels in the X-Api-Key header and is validated on every request.
The X-Api-Key header
| Field | Value |
|---|---|
| Name | X-Api-Key |
| Location | HTTP header on every request |
| Format | URL-safe base64 string (~43 characters, no human-readable prefix) |
| Generation | Configuración → Acceso API → «Agregar», in the app |
| Plan | Corporativo plan only; on other plans the key gets 403 |
| Validation | The server requires IsActive == true and ValidUntil >= now |
How to get your key
The key is issued from the app: in Configuración → Acceso API (Settings → API access), click «Agregar» and, in «Crear nueva llave API», enter the application name (for example, ERP — production) and the expiry date. The key stays in the credentials table, with a «Copiar» (copy) button; store it in your secrets manager. The section is only available on the Corporativo plan.
There is no public self-service issuance endpoint. If you need to rotate a key automatically, talk to the team to coordinate the flow.
Your first authenticated call
The following snippet lists customers in the workspace using the key injected as an environment variable.
GET /api/v1/customers
curl https://tuempresa.factura.com.do/api/v1/customers \ -H "X-Api-Key: $FACTURA_API_KEY"// list-customers.tsconst res = await fetch( "https://tuempresa.factura.com.do/api/v1/customers", { headers: { "X-Api-Key": process.env.FACTURA_API_KEY! } },);const { items, totalCount } = await res.json();# list_customers.pyimport osimport httpx
with httpx.Client(headers={"X-Api-Key": os.environ["FACTURA_API_KEY"]}) as c: r = c.get("https://tuempresa.factura.com.do/api/v1/customers") r.raise_for_status() print(r.json())<?php// list_customers.php$ch = curl_init("https://tuempresa.factura.com.do/api/v1/customers");curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["X-Api-Key: " . getenv("FACTURA_API_KEY")],]);$response = curl_exec($ch);curl_close($ch);echo $response;What a 401 looks like
If the key is missing or invalid, the server responds with 401 Unauthorized and no body. The ApiKeyFilter returns Results.Unauthorized() and ASP.NET closes the response with Content-Length: 0; your client must distinguish this case by the HTTP code, not the body.
HTTP/1.1 401 UnauthorizedContent-Length: 0Corporativo plan: the 403
REST API access is exclusive to the Corporativo plan. If the key is valid but the workspace is on another plan (or downgraded after issuing it), the routes for documents, notes, expenses, customers, suppliers, certification and signing respond 403 Forbidden with this body. Catalog routes (products, taxes, currencies, RNC and *-lookup queries) currently validate only the key; do not build your integration on that difference.
HTTP/1.1 403 ForbiddenContent-Type: application/json
{ "error": "El acceso a la API REST está disponible solo en el plan Corporativo." }