Document types
Factura Electrónica
Emití una Factura Electrónica (tipo 01) con servicios y mercancías, descuentos, IVA y venta a crédito.
This content is not available in your language yet.
La Factura Electrónica (document_type: "01") es el comprobante de venta estándar. Usala cuando le vendés a un cliente identificado: una empresa o una persona que necesita el comprobante a su nombre, por ejemplo para deducir el gasto o acreditar el IVA.
Si el cliente no se identifica (venta de mostrador), usá un Tiquete Electrónico. Si le vendés a un comprador en el exterior, usá la Factura de Exportación.
Qué la distingue
Sección titulada «Qué la distingue»| Campo | Regla en la FE |
|---|---|
receiver |
Obligatorio, con type, id y name |
document.activity_code |
Obligatorio: código de actividad económica del emisor (6 dígitos) |
issuer.address y issuer.email |
Obligatorios |
receiver.address |
Opcional; si lo enviás, provincia, cantón, distrito y señas |
receiver.activity_code |
Opcional; la actividad del receptor, si la conocés |
items[].tax |
Al menos un impuesto por línea. Una línea no sujeta a IVA lleva rate_code: "11" y rate: 0 |
items[].tariff_code |
No se permite: la partida arancelaria es solo para exportación |
commercial_info.sale_condition |
12 (mercancía no nacionalizada) y 13 (bienes usados) solo existen en la FE |
No hace falta enviar totales, clave ni consecutivo. Aster calcula el subtotal, el impuesto y el total de cada línea, arma el resumen y numera el comprobante por sucursal y terminal. Ver clave y consecutivo.
Ejemplo completo
Sección titulada «Ejemplo completo»Una venta de contado, pagada por transferencia, con dos líneas:
- La instalación de una estantería metálica (servicio) con IVA del 13 % (
rate_code: "08"). - Dos taladros percutores (mercancía) con un descuento comercial (
code: "07").
{ "document": { "document_type": "01", "activity_code": "475201", "date": "2026-10-08T10:15:00-06:00", "situation": "1", "branch": "001", "terminal": "00001" }, "commercial_info": { "currency": "CRC", "sale_condition": "01", "payment_method": "04" }, "issuer": { "type": "02", "id": "3101654321", "name": "Ferretería La Sabana S.A.", "commercial_name": "Ferretería La Sabana", "email": "facturas@ferreterialasabana.cr", "phone": "22905511", "address": { "province": "1", "canton": "08", "district": "01", "details": "Del Más x Menos 200 m sur" } }, "receiver": { "type": "01", "id": "109870654", "name": "Laura Jiménez Mora", "email": "laura.jimenez@example.com" }, "items": [ { "line_number": 1, "cabys_code": "8731000000000", "quantity": 1, "unit": "St", "description": "Instalación de estantería metálica en bodega", "price": 100000, "tax": [ { "type": "01", "rate_code": "08", "rate": 13 } ] }, { "line_number": 2, "cabys_code": "4423201000100", "quantity": 2, "unit": "Unid", "description": "Taladro percutor de 1/2 pulgada", "price": 45000, "discount": [ { "amount": 9000, "code": "07", "reason": "Descuento comercial" } ], "tax": [ { "type": "01", "rate_code": "08", "rate": 13 } ] } ]}Así calcula Aster cada línea y el resumen:
| Línea | Monto total | Descuento | Subtotal | IVA 13 % | Total línea |
|---|---|---|---|---|---|
| 1. Instalación (servicio) | 100 000 | 0 | 100 000 | 13 000 | 113 000 |
| 2. Taladros (mercancía) | 90 000 | 9 000 | 81 000 | 10 530 | 91 530 |
| Comprobante | 190 000 | 9 000 | 181 000 | 23 530 | 204 530 |
El IVA se calcula sobre el subtotal después del descuento: 81 000 × 13 % = 10 530. En el resumen, el servicio suma a servicios gravados (100 000) y los taladros a mercancías gravadas (90 000). Aster clasifica cada línea por el primer dígito del CABYS: 0 a 4 son mercancías, 5 a 9 son servicios.
Enviala
Sección titulada «Enviala»curl https://aster.astranexo.com/api/v1/electronic-documents \ -H "Authorization: Bearer aster_test_8KfQ2mVx3TzL9pRw" \ -H "Content-Type: application/json" \ -H "X-Idempotency-Key: pedido-1042" \ --data @factura.jsonimport { readFile } from 'node:fs/promises';
const body = await readFile('factura.json', 'utf8');
const res = await fetch('https://aster.astranexo.com/api/v1/electronic-documents', { method: 'POST', headers: { Authorization: `Bearer ${process.env.ASTER_API_KEY}`, 'Content-Type': 'application/json', 'X-Idempotency-Key': 'pedido-1042', }, body,});
const json = await res.json();if (!res.ok) { console.error(res.status, json.error);} else { console.log(json.data.document_key, json.data.status);}<?php$ch = curl_init('https://aster.astranexo.com/api/v1/electronic-documents');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer ' . getenv('ASTER_API_KEY'), 'Content-Type: application/json', 'X-Idempotency-Key: pedido-1042', ], CURLOPT_POSTFIELDS => file_get_contents('factura.json'),]);
$json = json_decode(curl_exec($ch), true);$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status === 201) { echo $json['data']['document_key'], ' ', $json['data']['status'], PHP_EOL;} else { echo $status, ' ', json_encode($json['error']), PHP_EOL;}import os
import requests
with open("factura.json", "rb") as f: body = f.read()
res = requests.post( "https://aster.astranexo.com/api/v1/electronic-documents", headers={ "Authorization": f"Bearer {os.environ['ASTER_API_KEY']}", "Content-Type": "application/json", "X-Idempotency-Key": "pedido-1042", }, data=body, timeout=30,)
payload = res.json()if res.status_code == 201: print(payload["data"]["document_key"], payload["data"]["status"])else: print(res.status_code, payload["error"])La llave decide el ambiente: con aster_test_ el comprobante va al ambiente de pruebas; con aster_live_, a producción. Por eso el cuerpo no lleva environment.
Respuesta
Sección titulada «Respuesta»{ "success": true, "message": "Document submitted for processing.", "data": { "id": 318, "document_key": "50608102600310165432100100001010000001042147201936", "consecutive_number": "00100001010000001042", "document_type": "01", "document_type_name": "Factura Electrónica", "status": "processing", "environment": "staging", "queued_at": "2026-10-08T16:15:02Z" }}El 201 significa que la factura pasó las validaciones, quedó firmada y se envió a Hacienda. El veredicto llega después: registrá un webhook para recibir document.accepted o document.rejected, o consultá GET /electronic-documents/{clave}. Ver ciclo de vida.
Venta a crédito
Sección titulada «Venta a crédito»Para una venta a crédito, usá sale_condition: "02" e indicá el plazo en días en credit_terms. Sin el plazo, la API responde 422.
{ "currency": "CRC", "sale_condition": "02", "credit_terms": "30", "payment_method": "04"}Errores que Aster detecta antes de firmar
Sección titulada «Errores que Aster detecta antes de firmar»Aster aplica las reglas de Hacienda antes de firmar. Si algo no cumple, responde 422 validation_error con el campo exacto en error.errors, y el consecutivo no se consume.
| Situación | Código de Hacienda | Qué hacer |
|---|---|---|
| La cédula del emisor o del receptor no está inscrita | -38 |
Verificá la cédula y el tipo de identificación |
| El CABYS no existe en el catálogo | -400 |
Buscalo en GET /reference/cabys?q=... |
La unidad no corresponde al CABYS (por ejemplo, Sp con un CABYS de mercancía) |
-110 / -111 |
Usá una unidad de servicio (Sp, Os, Spe, St, Al) solo con CABYS que empiezan con 5 a 9 |
CABYS exento facturado con una tarifa distinta de 10 |
-107 / -483 / -485 |
Usá rate_code: "10" en esa línea |
La tarifa no coincide con el código (por ejemplo, rate_code: "08" con rate: 4) |
-505 |
08 es 13 %, 04 es 4 %, 02 es 1 % |
rate_code 05, 06 o 07 en una factura |
— | Los códigos transitorios solo se aceptan en notas de crédito y débito |
| Fecha de emisión en el futuro | -53 |
Enviá la hora actual con zona -06:00, o no envíes date |
Clave propia cuya fecha no coincide con date |
-405 |
Las posiciones 4 a 9 de la clave son DDMMAA de la fecha de emisión |
Descuento sin code o sin reason |
— | Usá un código de la Nota 20 (07 es descuento comercial) |
Otros casos:
409 duplicate_consecutive: enviaste un consecutivo propio que ya usaste en ese ambiente. Un consecutivo enviado a Hacienda no se reutiliza nunca, ni siquiera si el comprobante fue rechazado.422 organization_mismatch: la cédula deissuer.idno es la de la organización de tu llave.
Ver el catálogo completo en errores.
Siguientes pasos
Sección titulada «Siguientes pasos»- Nota de crédito: devoluciones y anulaciones parciales.
- Anular un comprobante: anulación total en una llamada.
- PDF y correo: enviale la factura al cliente.