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-09-02",
"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.
Para notas de crédito, related_invoice_id (opcional) referencia el id de la factura que se acredita:
se informa como comprobante asociado a ARCA y, para los ítems con product_id sin tax_rate explícito,
la NC usa la alícuota con la que se facturó ese producto en la factura original (no la alícuota actual del producto,
que pudo haber cambiado desde la emisión).
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, INVALID_RELATED_INVOICE (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 por WhatsApp