Empezar
Inicio rápido
Creá una cuenta, obtené tu llave de prueba y enviá tu primera Factura Electrónica en cinco minutos.
En esta guía enviás una Factura Electrónica (tipo 01) en modo de prueba y leés el veredicto de Hacienda. No necesitás certificado ni plan pagado.
-
Creá tu cuenta
Registrate en /app/signup con tu correo y confirmalo. Después, en Organizaciones, agregá tu primera organización (el emisor) con su cédula, nombre y actividad económica.
Tu cuenta arranca en el plan Sandbox: modo de prueba gratis e ilimitado.
-
Copiá tu llave de prueba
En el portal, abrí Llaves de API y creá una llave de prueba para tu organización. Empieza con
aster_test_. Se muestra una sola vez: guardala en una variable de entorno.Terminal export ASTER_API_KEY="aster_test_8KfQ2mVx3TzL9pRw"La llave decide el ambiente: una llave
aster_test_siempre trabaja contra el ambiente de pruebas. Más detalles en autenticación. -
Prepará la factura
Guardá este JSON como
factura.json. Es una factura de contado por dos taladros con IVA del 13 %. No hace falta enviar totales, clave ni consecutivo: Aster los calcula.factura.json {"document": {"document_type": "01","activity_code": "475201","branch": "001","terminal": "00001"},"commercial_info": {"currency": "CRC","sale_condition": "01","payment_method": "01"},"issuer": {"type": "02","id": "3101654321","name": "Ferretería La Sabana S.A.","email": "facturas@ferreterialasabana.cr","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": [{"cabys_code": "4423201000100","quantity": 2,"unit": "Unid","description": "Taladro percutor de 1/2 pulgada","price": 15000,"tax": [{ "type": "01", "rate_code": "08", "rate": 13 }]}]} -
Envíala
Hacé un
POST /electronic-documents. El encabezadoX-Idempotency-Keyes opcional pero recomendado: si repetís la misma solicitud con la misma llave, Aster devuelve la respuesta original en vez de emitir otra factura.Terminal curl https://aster.astranexo.com/api/v1/electronic-documents \-H "Authorization: Bearer $ASTER_API_KEY" \-H "Content-Type: application/json" \-H "X-Idempotency-Key: pedido-1042" \--data @factura.jsonenviar.mjs import { 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,});console.log(res.status, await res.json());enviar.php <?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'),]);$body = curl_exec($ch);$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);echo $status, PHP_EOL, $body, PHP_EOL;enviar.py import osimport requestswith 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,)print(res.status_code, res.json())main.go package mainimport ("fmt""io""net/http""os")func main() {body, err := os.Open("factura.json")if err != nil {panic(err)}defer body.Close()req, err := http.NewRequest(http.MethodPost,"https://aster.astranexo.com/api/v1/electronic-documents", body)if err != nil {panic(err)}req.Header.Set("Authorization", "Bearer "+os.Getenv("ASTER_API_KEY"))req.Header.Set("Content-Type", "application/json")req.Header.Set("X-Idempotency-Key", "pedido-1042")res, err := http.DefaultClient.Do(req)if err != nil {panic(err)}defer res.Body.Close()out, _ := io.ReadAll(res.Body)fmt.Println(res.StatusCode, string(out))} -
Leé la respuesta
Aster responde
201 Createden cuanto validó, firmó y puso el comprobante en camino a Hacienda. No espera el veredicto.201 Created {"success": true,"message": "Document submitted successfully","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:20:11Z"},"timestamp": "2026-10-08T16:20:11Z","api_version": "1.0"}document_keyes la clave de 50 dígitos. Guardala: identifica el comprobante ante Hacienda y en Aster.consecutive_numberes el consecutivo de 20 dígitos que Aster asignó.status: "processing"significa que el comprobante va camino a Hacienda. El veredicto llega en segundos.
Si la validación falla, la respuesta es
422 validation_errorcon la lista de campos enerror.errors. Ver errores. -
Obtené el veredicto
Consultá el comprobante por su clave hasta que
statusseaacceptedorejected. Un intervalo de 2 a 5 segundos es suficiente.Terminal curl https://aster.astranexo.com/api/v1/electronic-documents/50608102600310165432100100001010000001042147201936 \-H "Authorization: Bearer $ASTER_API_KEY"consultar.mjs const clave = '50608102600310165432100100001010000001042147201936';const res = await fetch(`https://aster.astranexo.com/api/v1/electronic-documents/${clave}`, {headers: { Authorization: `Bearer ${process.env.ASTER_API_KEY}` },});const { data } = await res.json();console.log(data.status, data.hacienda_message);consultar.php <?php$clave = '50608102600310165432100100001010000001042147201936';$ch = curl_init("https://aster.astranexo.com/api/v1/electronic-documents/{$clave}");curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('ASTER_API_KEY')],]);$data = json_decode(curl_exec($ch), true)['data'];echo $data['status'], ' ', $data['hacienda_message'], PHP_EOL;consultar.py import osimport requestsclave = "50608102600310165432100100001010000001042147201936"res = requests.get(f"https://aster.astranexo.com/api/v1/electronic-documents/{clave}",headers={"Authorization": f"Bearer {os.environ['ASTER_API_KEY']}"},timeout=30,)data = res.json()["data"]print(data["status"], data["hacienda_message"])main.go package mainimport ("fmt""io""net/http""os")func main() {clave := "50608102600310165432100100001010000001042147201936"req, err := http.NewRequest(http.MethodGet,"https://aster.astranexo.com/api/v1/electronic-documents/"+clave, nil)if err != nil {panic(err)}req.Header.Set("Authorization", "Bearer "+os.Getenv("ASTER_API_KEY"))res, err := http.DefaultClient.Do(req)if err != nil {panic(err)}defer res.Body.Close()out, _ := io.ReadAll(res.Body)fmt.Println(string(out))}200 OK (extracto) {"success": true,"data": {"id": 318,"document_key": "50608102600310165432100100001010000001042147201936","consecutive_number": "00100001010000001042","document_type": "01","status": "accepted","environment": "staging","emisor_name": "Ferretería La Sabana S.A.","emisor_identification": "3101654321","receptor_name": "Laura Jiménez Mora","receptor_identification": "109870654","total_amount": 33900,"tax_amount": 3900,"net_amount": 30000,"currency": "CRC","hacienda_status": "aceptado","hacienda_message": "Documento aceptado"}}En producción conviene no consultar en ciclo: registrá un webhook y Aster te avisa con
document.acceptedodocument.rejected. Ver la guía de webhooks.
Pasar a producción
Sección titulada «Pasar a producción»Cuando tu integración funciona en pruebas, estos son los pasos para emitir comprobantes reales:
- Elegí un plan pagado en el portal, en Facturación. Las llaves de producción solo se pueden crear con un plan activo.
- Subí el certificado de producción: el archivo
.p12de firma de Hacienda y su PIN. La cédula del certificado tiene que coincidir con la de la organización. - Configurá las credenciales de Hacienda de producción (usuario y contraseña del sistema de comprobantes electrónicos). El portal las verifica contra Hacienda en el momento.
- Creá una llave
aster_live_en Llaves de API y reemplazá la de prueba en tu servidor. No hace falta cambiar nada más en las solicitudes: la llave decide el ambiente. - Registrá un webhook para recibir los veredictos sin consultar en ciclo.
- Revisá la numeración. Los consecutivos de producción son independientes de los de prueba y arrancan en 1 por sucursal, terminal y tipo. Si venís de otro proveedor, leé migrar.
Los comprobantes de producción con veredicto final de Hacienda cuentan para el uso de tu plan. Si llegás al límite, mejorá de plan o agregá un paquete en cualquier momento desde el portal.