Referencia técnica de la API REST v1 de Profactur. Base URL: https://profactur.com/api/v1
El módulo Integraciones expone una API REST para operar tu cuenta de Profactur desde tus propios sistemas: emitir facturas con CAE de ARCA, consultar comprobantes, administrar clientes y productos, y recibir notificaciones por webhooks.
Sin ambos requisitos, la API responde 403 (ver Autenticación).
En el panel, andá a Configuración → Integraciones → API REST, completá un nombre, elegí los scopes que necesitás y generá la clave. La clave cruda se muestra una sola vez: guardala en un lugar seguro, no se vuelve a mostrar.
curl -X GET https://profactur.com/api/v1/account \
-H "Authorization: Bearer TU_API_KEY"
Todas las requests requieren el header:
Authorization: Bearer {tu_api_key}
Cada API Key tiene asignados uno o más scopes que limitan a qué endpoints puede acceder.
| Scope | Permite | Endpoints |
|---|---|---|
account:read | Consultar cuenta y consumo | GET /account, GET /account/usage |
invoices:read | Consultar comprobantes | GET /invoices, GET /invoices/{id}, GET /invoices/{id}/pdf |
invoices:write | Emitir comprobantes | POST /invoices |
customers:read | Consultar clientes | GET /customers, GET /customers/{id} |
customers:write | Crear y editar clientes | POST /customers, PUT /customers/{id} |
products:read | Consultar productos | GET /products, GET /products/{id} |
webhooks:manage | Administrar webhooks | GET /webhooks, POST /webhooks, DELETE /webhooks/{id} |
| Código | HTTP | Descripción |
|---|---|---|
INVALID_API_KEY | 401 | La key no existe o fue revocada |
INTEGRATIONS_MODULE_INACTIVE | 403 | El módulo Integraciones no está activo |
PLAN_REQUIRED | 403 | Se requiere un plan ProFactur activo |
INSUFFICIENT_SCOPE | 403 | La key no tiene el scope necesario |
Las keys sandbox permiten desarrollar y probar tu integración sin emitir
facturas reales, sin consumir cuota del plan y sin escribir datos en tu cuenta. Se crean
desde Configuración → Integraciones eligiendo el ambiente
«Sandbox» — se distinguen a simple vista por el prefijo pf_test_
(producción usa pf_live_). Podés tener hasta 2 keys sandbox
activas, que no cuentan para el límite de keys de tu plan. No hace falta tener el
certificado ARCA configurado: podés probar la API antes de terminar el setup fiscal.
Sandbox NO es «producción con un flag». Diferencias que tenés que conocer antes de integrar:
POST /invoices sandbox no crea el comprobante: GET /invoices/{id} posterior devuelve 404 y no vas a verlo en el panel. Es intencional — el sandbox no contamina numeración fiscal, Libro IVA ni reportes.9 (los CAE reales de ARCA no empiezan con 9) y vencimiento a +10 días. No sirve para imprimir comprobantes válidos.POST/DELETE /webhooks con key sandbox devuelve 403 SANDBOX_UNSUPPORTED. Para probar la recepción de webhooks usá una key de producción.| Endpoint | Con key sandbox |
|---|---|
POST /invoices | Validación completa (tipos, cliente, punto de venta) + emisión simulada: responde 201 con id: 0, voucher_number: 0, CAE simulado y sandbox: true. No llama a ARCA ni consume cuota. |
POST/PUT /customers | Validación completa + echo simulado con id: 0 y sandbox: true. No persiste. |
GET (invoices, customers, products, account) | Leen tus datos reales — solo lectura, sin efectos. |
POST/DELETE /webhooks | 403 SANDBOX_UNSUPPORTED. |
Toda respuesta de escritura simulada incluye meta.environment: "sandbox" y
data.sandbox: true (redundante a propósito, para que tu logging distinga el
ambiente sin ambigüedad). El rate limit en sandbox es el de tu plan × 3.
curl -X POST https://profactur.com/api/v1/invoices \
-H "Authorization: Bearer pf_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"invoice_type": "FC_B",
"point_of_sale_id": 3,
"customer": { "name": "Juan Pérez", "document_type": "DNI", "document_number": "30111222" },
"items": [ { "description": "Test", "quantity": 1, "unit_price": 1000, "tax_rate": 21 } ]
}'
{
"success": true,
"data": {
"id": 0,
"full_number": "FC B 00003-00000000",
"voucher_number": 0,
"cae": "91234567890123",
"cae_due_date": "2026-07-15",
"is_fiscalized": true,
"sandbox": true,
"total": 1210.0
},
"meta": { "request_id": "…", "timestamp": "…", "environment": "sandbox" }
}
Todas las respuestas usan el mismo envelope: { success, data, meta } en éxito; { success, error, meta } en error (ver Errores).
/api/v1/accountDatos de la cuenta y plan activo. Scope: account:read
curl https://profactur.com/api/v1/account \
-H "Authorization: Bearer TU_API_KEY"
{
"success": true,
"data": {
"company": {
"id": 2,
"name": "Mi Empresa S.R.L.",
"fantasy_name": "Mi Empresa",
"cuit": "30712345678",
"tax_condition": "RI",
"is_demo": false,
"can_fiscalize": true
},
"plan": {
"name": "Mediano",
"slug": "mediano",
"invoices_per_month": 5000
}
},
"meta": { "request_id": "9b1c...", "timestamp": "2026-06-29T12:00:00-03:00" }
}
/api/v1/account/usageConsumo del mes actual vs. el límite del plan. Scope: account:read
{
"success": true,
"data": {
"period": "2026-06",
"invoices_this_month": 120,
"invoices_limit": 5000,
"invoices_remaining": 4880,
"unlimited": false
},
"meta": { "request_id": "...", "timestamp": "..." }
}
/api/v1/invoicesListado paginado (50 por página). Filtros opcionales: desde, hasta (fecha YYYY-MM-DD), status (draft, confirmed, fiscal_pending, fiscalized, cancelled) y source (web, api, pos, batch — origen del comprobante; usá source=api para reconciliar solo lo emitido desde tu integración). Scope: invoices:read
curl "https://profactur.com/api/v1/invoices?desde=2026-06-01&status=fiscalized&source=api" \
-H "Authorization: Bearer TU_API_KEY"
{
"success": true,
"data": [
{
"id": 1024,
"full_number": "00003-00000128",
"voucher_number": 128,
"voucher_type": { "afip_code": 6, "letter": "B", "short_name": "FC B", "name": "Factura B" },
"date": "2026-06-29",
"customer": { "id": 55, "name": "Juan Pérez", "document_type": "DNI", "document_number": "30111222", "tax_condition": "CF" },
"currency": "ARS",
"subtotal": 1000.00,
"tax_amount": 210.00,
"total": 1210.00,
"status": "fiscalized",
"payment_status": "pending",
"source": "api",
"cae": "75123456789012",
"cae_due_date": "2026-07-09",
"is_fiscalized": true,
"created_at": "2026-06-29T12:00:00-03:00"
}
],
"meta": {
"request_id": "...", "timestamp": "...",
"pagination": { "total": 128, "per_page": 50, "current_page": 1, "last_page": 3 }
}
}
/api/v1/invoicesEmite una factura y solicita el CAE a ARCA. Scope: invoices:write. Este es el único endpoint que consume cuota facturable (cuando el CAE se emite con éxito).
invoice_type admite FC_A, FC_B, FC_C, ND_A/B/C, NC_A/B/C.
Los comprobantes letra A requieren customer_id de un cliente registrado (no admiten cliente inline).
Para B/C podés mandar customer_id o un objeto customer inline.
curl -X POST https://profactur.com/api/v1/invoices \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"invoice_type": "FC_B",
"point_of_sale_id": 3,
"customer": {
"name": "Juan Pérez",
"document_type": "DNI",
"document_number": "30111222",
"address": "Av. Siempreviva 742"
},
"items": [
{
"description": "Servicio de consultoría",
"quantity": 1,
"unit_price": 1000.00,
"discount_percent": 0,
"tax_rate": 21
}
],
"date": "2026-06-29"
}'
Respuesta 201 Created con el comprobante (mismo formato que el detalle, incluyendo items y el cae).
Errores específicos: INVALID_CUSTOMER, INVALID_POINT_OF_SALE, INVALID_PRODUCT, INVALID_VOUCHER_TYPE (422); INVOICE_NOT_ALLOWED (422, cuenta demo o sin certificado ARCA); AFIP_ERROR (502, ARCA rechazó el comprobante).
/api/v1/invoices/{id}Detalle de un comprobante, con sus items. Scope: invoices:read. 404 NOT_FOUND si no pertenece a tu empresa.
/api/v1/invoices/{id}/pdfDevuelve el PDF del comprobante (Content-Type: application/pdf, inline). Scope: invoices:read
/api/v1/customersListado paginado (50 por página). Filtro opcional search (nombre, documento o CUIT). Scope: customers:read
/api/v1/customersCrea un cliente. Scope: customers:write. tax_condition: CF, RI, MT, EX, NR.
curl -X POST https://profactur.com/api/v1/customers \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ACME S.A.",
"customer_type": "company",
"document_type": "CUIT",
"tax_id": "30712345678",
"tax_condition": "RI",
"email": "[email protected]"
}'
{
"success": true,
"data": {
"id": 56,
"name": "ACME S.A.",
"fantasy_name": null,
"customer_type": "company",
"document_type": "CUIT",
"document_number": null,
"tax_id": "30712345678",
"tax_condition": "RI",
"email": "[email protected]",
"phone": null,
"mobile": null,
"address": null,
"city": null,
"state": null,
"zip": null,
"credit_limit": 0,
"payment_term_days": 0,
"is_active": true,
"created_at": "2026-06-29T12:00:00-03:00"
},
"meta": { "request_id": "...", "timestamp": "..." }
}
/api/v1/customers/{id}Detalle de un cliente. Scope: customers:read
/api/v1/customers/{id}Actualiza un cliente (campos opcionales; company_id nunca se reasigna). Scope: customers:write
/api/v1/productsListado paginado (50 por página). Filtros: search (nombre, SKU, código de barras) y active_only. Scope: products:read
{
"success": true,
"data": [
{
"id": 7,
"sku": "SRV-001",
"barcode": null,
"name": "Servicio de consultoría",
"description": null,
"cost_price": 0,
"tax_rate": 21,
"is_taxable": true,
"is_service": true,
"track_stock": false,
"is_active": true,
"created_at": "2026-06-29T12:00:00-03:00"
}
],
"meta": { "request_id": "...", "timestamp": "...", "pagination": { "total": 1, "per_page": 50, "current_page": 1, "last_page": 1 } }
}
/api/v1/products/{id}Detalle de un producto. Scope: products:read
/api/v1/webhooksEndpoints de webhook registrados. Scope: webhooks:manage
/api/v1/webhooksRegistra un endpoint. Scope: webhooks:manage. La url debe ser HTTPS. El secret de firma se devuelve una sola vez en la respuesta.
curl -X POST https://profactur.com/api/v1/webhooks \
-H "Authorization: Bearer TU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tu-sistema.com/webhooks/profactur",
"events": ["invoice.created", "invoice.cae_approved"]
}'
{
"success": true,
"data": {
"id": 4,
"url": "https://tu-sistema.com/webhooks/profactur",
"events": ["invoice.created", "invoice.cae_approved"],
"is_active": true,
"last_triggered_at": null,
"created_at": "2026-06-29T12:00:00-03:00",
"secret": "whsec_xxxxxxxxxxxxxxxxxxxx"
},
"meta": { "request_id": "...", "timestamp": "..." }
}
/api/v1/webhooks/{id}Elimina un endpoint. Scope: webhooks:manage. Devuelve { "deleted": true }.
Solo un POST /api/v1/invoices que resulte en un CAE emitido con éxito. Una factura emitida vía API = un evento facturable.
GET).422).401 / 403).En el panel: Configuración → Integraciones → Consumo. Ahí ves las facturas usadas del mes, el límite de tu plan y el excedente.
El servicio continúa activo: no se bloquean las emisiones. El excedente se factura manualmente según el costo por 1.000 facturas de tu plan (ver tabla de planes).
Usá POST /api/v1/webhooks con url (HTTPS requerido) y events (array). Guardá el secret que se devuelve una sola vez.
invoice.created — se creó un comprobante.invoice.cae_approved — ARCA aprobó el CAE del comprobante.
Cada entrega incluye los headers X-ProFactur-Signature y X-ProFactur-Event.
La firma es un HMAC-SHA256 del cuerpo crudo recibido, con el prefijo sha256=.
Verificala con hash_equals sobre los bytes exactos del body:
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PROFACTUR_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (! hash_equals($expected, $signature)) {
http_response_code(401);
exit;
}
Si tu endpoint no responde 2xx, reintentamos hasta 3 veces con backoff de 60s → 300s → 900s.
El límite de requests por minuto y el cupo mensual de facturas dependen de tu plan Integrador:
| Plan | Req/min | Facturas/mes | Precio | Excedente /1.000 |
|---|---|---|---|---|
| Starter | 30 | 1.000 | USD 99 | USD 60 |
| Pro | 60 | 4.000 | USD 199 | USD 50 |
| Business | 120 | 8.000 | USD 349 | USD 25 |
| Enterprise | 200 | 20.000 | USD 599 | USD 12 |
Cada respuesta incluye los headers de rate limit:
| Header | Descripción |
|---|---|
X-RateLimit-Limit | Límite de requests por minuto de tu plan |
X-RateLimit-Remaining | Requests restantes en la ventana actual |
X-RateLimit-Reset | Timestamp Unix en que se reinicia la ventana |
Al superar el límite, la API responde 429 RATE_LIMIT_EXCEEDED. Esperá los segundos indicados en el header Retry-After antes de reintentar.
Las keys sandbox tienen su propio bucket con el límite del plan × 3.
| Header | Descripción |
|---|---|
X-Billable-Events-Month | Facturas emitidas vía API este mes |
X-Billable-Events-Remaining | Facturas restantes del cupo mensual (negativo si hay excedente) |
Todos los errores usan el mismo envelope:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Descripción del error"
},
"meta": {
"request_id": "uuid",
"timestamp": "2026-06-29T12:00:00Z"
}
}
En errores de validación, error.details incluye los campos inválidos.
| Código | HTTP | Descripción |
|---|---|---|
INVALID_API_KEY | 401 | La key no existe o fue revocada |
INTEGRATIONS_MODULE_INACTIVE | 403 | El módulo Integraciones no está activo |
PLAN_REQUIRED | 403 | Se requiere un plan ProFactur activo |
INSUFFICIENT_SCOPE | 403 | La key no tiene el scope necesario |
RATE_LIMIT_EXCEEDED | 429 | Superaste el límite de requests por minuto |
NOT_FOUND | 404 | El recurso no existe o no pertenece a tu empresa |
VALIDATION_ERROR | 422 | Datos inválidos (detalle en error.details) |
INVOICE_NOT_ALLOWED | 422 | La cuenta no puede emitir (demo, sin certificado, o límite de plan) |
SANDBOX_UNSUPPORTED | 403 | Operación no disponible con key sandbox (ver Sandbox) |
AFIP_ERROR | 502 | ARCA rechazó el comprobante |
INTERNAL_ERROR | 500 | Error interno inesperado |
Un AFIP_ERROR con HTTP 502 significa que ARCA rechazó el comprobante.
El motivo concreto devuelto por ARCA viene en el campo message del error, y
error.details incluye arca_code (código del error primario) y
arca_errors (lista cruda de errores del webservice).
Para los códigos más frecuentes, el envelope suma un campo hint: una explicación
en español orientada a la acción, para resolver el rechazo sin buscar en los manuales de ARCA.
Si el código no está catalogado, hint no aparece.
{
"success": false,
"error": {
"code": "AFIP_ERROR",
"message": "[10018] El campo ImpIVA es distinto a la suma de los importes por alícuota",
"details": {
"arca_code": "10018",
"arca_errors": [ { "Code": 10018, "Msg": "..." } ]
},
"hint": "El desglose de IVA no coincide con el importe declarado. ImpIVA debe ser la suma exacta de los importes por alícuota."
},
"meta": { "request_id": "uuid", "timestamp": "2026-07-04T12:00:00Z" }
}
| Código ARCA | Hint |
|---|---|
600 | El certificado usado no corresponde al CUIT emisor (ValidacionDeToken). Verificá en ARCA que el servicio wsfe esté delegado al certificado de tu empresa. |
601 | El CUIT autenticado no coincide con el CUIT emisor del comprobante. El emisor debe ser el mismo CUIT con el que se generó el certificado. |
10000 | Tu CUIT no está autorizado a emitir comprobantes clase A. Consultá con tu contador la habilitación en ARCA. |
10005 | El punto de venta no existe en ARCA o no está habilitado para facturación por Web Services. Verificá en ARCA → Administración de puntos de venta que el punto sea de tipo "Web Services". |
10013 | El número de documento (DocNro) del receptor es inválido para el tipo de documento informado. CUIT y CUIL van con 11 dígitos, sin guiones ni espacios. |
10015 | Falta identificar al receptor: a partir de cierto importe el consumidor final debe informarse con DNI o CUIT. Revisá el tipo y número de documento del cliente. |
10246 | Falta o es inválida la condición frente al IVA del receptor (RG 5616). Verificá la condición fiscal del cliente en ProFactur antes de emitir. |
10016 | El número o la fecha del comprobante no se corresponde con el próximo a autorizar. Suele indicar numeración desfasada del punto de venta o fecha fuera del rango permitido (5 días hacia atrás para productos, 10 para servicios). |
10018 | El desglose de IVA no coincide con el importe declarado. ImpIVA debe ser la suma exacta de los importes por alícuota. |
10023 | Los importes de IVA por alícuota no cierran contra sus bases imponibles (tolerancia 0,01%). Recalculá cada IVA como base × alícuota con redondeo a 2 decimales. |
10192 | El comprobante cae bajo el régimen de Factura de Crédito Electrónica (Ley 27.440). Para receptores grandes empresas corresponde emitir FCE (tipos 201/206/211). |
500 | Error interno de ARCA. No es un problema de tu request: reintentá en unos minutos. |
501 | Error interno de base de datos de ARCA. No es un problema de tu request: reintentá en unos minutos. |
502 | Error interno de base de datos de ARCA. No es un problema de tu request: reintentá en unos minutos. |
503 | El servicio de ARCA no está disponible. Reintentá en unos minutos. |
CONFIG | La configuración ARCA de la cuenta está incompleta. Revisá el CUIT y el certificado en Configuración → Facturación Electrónica. |
CERT | El certificado ARCA de la cuenta es inválido o expiró. Regenerá el certificado desde Configuración → Facturación Electrónica. |
SERVICE | El servicio de ARCA no está disponible en este momento. Reintentá en unos minutos. |
Los códigos CONFIG, CERT y SERVICE no vienen de ARCA:
son errores de configuración de la cuenta detectados por Profactur antes de llamar al webservice.
¿Necesitás ayuda? Escribinos a [email protected]