Factura SDK
Emisores

Emisores

Los CUITs que facturan: alta, estados, punto de venta, certificado, delegación, verificación y borrado.


El emisor es el CUIT que figura como vendedor en el comprobante. Cada emisor tiene un único punto de venta y un certificado, y recién emite cuando está verificado. Lo identificás por su CUIT: es lo que mandás en issuer_cuit al emitir.

Endpoints

Método y rutaQué hace
POST /v1/issuersCrea un emisor.
GET /v1/issuersLista los emisores, con filtros y paginación.
GET /v1/issuers/:idDevuelve un emisor.
PUT /v1/issuers/:idModifica un emisor: datos, punto de venta, certificado o estado.
DELETE /v1/issuers/:idBorra un emisor. Sus comprobantes quedan.
GET /v1/issuers/lookup?tax_id=Devuelve los datos de la constancia de inscripción de un CUIT, para dar de alta el emisor.
POST /v1/issuers/sales-pointsLista los puntos de venta de un CUIT en ARCA, con su clave fiscal.
POST /v1/issuers/sales-points/createCrea en ARCA un punto de venta de web services para un CUIT, con su clave fiscal.
POST /v1/issuers/:id/certificateCrea un certificado para el emisor y se lo asigna. Ver Certificados.
POST /v1/issuers/:id/delegationAutoriza en ARCA que el certificado de otro CUIT firme por el emisor.
POST /v1/issuers/:id/verifyVerifica el emisor: emite una factura de $1 y su nota de crédito. Lo pasa a active.

El emisor

{
  "id": "0f8f3c2a-5b1e-4c7d-9a2e-6d4b8e1f2a3c",
  "tax_id": "20111111112",
  "business_name": "Emisor de prueba",
  "address": "Av. Siempre Viva 742, CABA",
  "vat_condition": 1,
  "gross_income": "20111111112",
  "activity_start_date": "2020-01-01",
  "sales_point": 1,
  "certificate_id": "c3a1e7d9-8b2f-4e6a-a1d4-5f7b9c0e2d31",
  "status": "active",
  "verified_at": "2026-10-14T14:03:00.000Z",
  "created_at": "2026-10-14T14:00:00.000Z",
  "updated_at": "2026-10-14T14:03:00.000Z"
}
CampoDescripción
idIdentificador del emisor. Se usa en las rutas /v1/issuers/:id.
tax_idCUIT, 11 dígitos. Único por proyecto entre los emisores no borrados. Es el issuer_cuit al emitir.
business_nameRazón social, impresa en el comprobante.
addressDomicilio comercial, impreso en el comprobante.
vat_conditionCondición frente al IVA. Define qué comprobantes puede emitir. Ver condiciones frente al IVA.
gross_incomeNúmero de ingresos brutos, impreso en el comprobante.
activity_start_dateInicio de actividades, YYYY-MM-DD, impreso en el comprobante.
sales_pointPunto de venta por el que salen sus comprobantes, o null. Ver punto de venta.
certificate_idCertificado con el que firma, o null. Ver certificado.
statuspending, active o inactive. Ver estados.
verified_atCuándo se verificó, o null.

Estados

EstadoQué significa
pendingRecién creado. No emite. Pasa a active al verificarlo.
activeVerificado. Emite.
inactivePausado. No emite hasta que lo vuelvas a poner active.
deletedBorrado. No aparece en los listados ni en el detalle; sus comprobantes quedan.

El pase a active es automático al verificar: no se puede setear a mano. PUT solo acepta status active o inactive, y solo si el emisor ya fue verificado alguna vez (verified_at).

Crear un emisor

POST /v1/issuers crea el emisor. Los datos fiscales se imprimen en cada comprobante, por eso son obligatorios. El punto de venta y el certificado podés darlos acá o después.

Solicitud
const response = await fetch('https://app.afipsdk.com/api/v1/issuers', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    tax_id: '20111111112',
    business_name: 'Emisor de prueba',
    address: 'Av. Siempre Viva 742, CABA',
    vat_condition: 1,
    gross_income: '20111111112',
    activity_start_date: '2020-01-01',
    sales_point: 1,
    certificate_id: 'c3a1e7d9-8b2f-4e6a-a1d4-5f7b9c0e2d31'
  })
});

const issuer = await response.json();
CampoTipoRequeridoDescripción
tax_idstringSíCUIT válido, 11 dígitos sin guiones. No se puede cambiar después.
business_namestringSíRazón social. Hasta 200 caracteres.
addressstringSíDomicilio. Hasta 300 caracteres.
vat_conditionintegerSíCondición frente al IVA.
gross_incomestringSíNúmero de ingresos brutos. Hasta 50 caracteres.
activity_start_datestringSíInicio de actividades, YYYY-MM-DD.
sales_pointintegerNoPunto de venta, de 1 a 99999.
certificate_idstringNoUn certificado activo. Ver Certificados.

En los campos opcionales, null o "" equivale a no mandarlos.

Datos de la constancia de inscripción

Para no cargar los datos a mano, GET /v1/issuers/lookup?tax_id= devuelve lo que figura en la constancia de inscripción del CUIT en ARCA: razón social, domicilio fiscal, condición frente al IVA e inicio de actividades. No guarda nada: vos elegís qué mandar a POST /v1/issuers.

Solicitud
const response = await fetch('https://app.afipsdk.com/api/v1/issuers/lookup?tax_id=20111111112', {
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>'
  }
});

const { issuer, unresolved } = await response.json();
{
  "tax_id": "20111111112",
  "synced_at": "2026-10-14T13:58:00.000Z",
  "issuer": {
    "business_name": "PEREZ JUAN",
    "address": "AV SIEMPRE VIVA 742 - CIUDAD AUTONOMA BUENOS AIRES",
    "vat_condition": 1,
    "activity_start_date": "2020-01-01"
  },
  "unresolved": [],
  "warnings": [],
  "taxpayer": { "...": "el contribuyente según ARCA" },
  "inscription_proof": { "...": "la constancia completa" }
}

unresolved lista los campos que no se pudieron resolver desde la constancia (business_name, address, vat_condition o activity_start_date); warnings avisa si el CUIT no está activo en ARCA. activity_start_date es el primer día del período de actividad más antiguo. El número de ingresos brutos y el punto de venta nunca salen de acá. La consulta es siempre al padrón real, también desde el sandbox.

Certificado

ARCA exige firmar cada comprobante con un certificado digital. El emisor firma con el certificado de certificate_id, mas detalles en Certificados.

Punto de venta

Cada emisor tiene un solo punto de venta (sales_point), por el que salen todos sus comprobantes.

Tiene que ser un punto de venta del CUIT habilitado en ARCA para facturación electrónica por web services. Si no sabés cuál es, podes listar los puntos de ventas con: POST /v1/issuers/sales-points.

Solicitud
const response = await fetch('https://app.afipsdk.com/api/v1/issuers/sales-points', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    tax_id: '20111111112',
    username: '20111111112',
    password: '<CLAVE_FISCAL>'
  })
});

const { automation_id } = await response.json();
CampoTipoRequeridoDescripción
tax_idstringSíCUIT del que se listan los puntos de venta.
usernamestringSíUsuario de ARCA (normalmente el mismo CUIT).
passwordstringSíClave fiscal. No se guarda.

Ver como obtener la respuesta de una Automatización

{
  "id": "a9e2c4b6-1d3f-4a5b-8c7d-2e4f6a8b0c1d",
  "status": "complete",
  "data": {
    "tax_id": "20111111112",
    "sales_points": [
      { "number": 1, "system": "RECE1 - FACTURA ELECTRONICA - WEB SERVICES", "display_name": "Casa central", "address": "Av. Siempre Viva 742", "blocked": false, "deactivated": false },
      { "number": 3, "system": "RECE1 - FACTURA ELECTRONICA - WEB SERVICES", "display_name": "Depósito", "address": "Ruta 8 km 42", "blocked": true, "deactivated": false }
    ],
    "next_number": 4
  }
}

next_number es el número que tendría un punto de venta nuevo: uno más que el último de todos los del CUIT, sean de web services o no.

Elegí uno que no esté blocked ni deactivated (la lista ya trae solo los de web services), y asignalo al emisor con PUT /v1/issuers/:id:

{
  "sales_point": 1
}

Si la clave fiscal es incorrecta, la automatización termina en error: GET /v1/automations/:id responde 400 con el motivo en data.message. En sandbox, password: "INVALID_PASSWORD" simula ese caso.

Crear un punto de venta

Si el CUIT no tiene un punto de venta de web services, o querés uno aparte para la API, POST /v1/issuers/sales-points/create lo da de alta en ARCA con la clave fiscal: para facturación electrónica por web services, con el número que sigue al último del CUIT y el sistema que corresponde a la condición frente al IVA del emisor. ARCA pide que el CUIT tenga un domicilio cargado; si no lo tiene, la automatización termina en error.

Solicitud
const response = await fetch('https://app.afipsdk.com/api/v1/issuers/sales-points/create', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    tax_id: '20111111112',
    username: '20111111112',
    password: '<CLAVE_FISCAL>',
    vat_condition: 1
  })
});

const { automation_id } = await response.json();
CampoTipoRequeridoDescripción
tax_idstringSíCUIT para el que se crea.
usernamestringSíUsuario de ARCA (normalmente el mismo CUIT).
passwordstringSíClave fiscal. No se guarda.
vat_conditionintegerNoCondición frente al IVA del emisor, del mismo catálogo que vat_condition del emisor: elige el sistema de ARCA (responsable inscripto, monotributo o exento). Sin ella se pide el de responsable inscripto y, si ARCA no lo ofrece para el CUIT, el único de web services que ofrezca.
numberintegerNoNúmero del punto de venta, de 1 a 99999. Por defecto, next_number.
namestringNoNombre de fantasía con el que queda en ARCA, hasta 50 caracteres. Por defecto, Factura SDK.
systemstringNoSistema de ARCA, por código o por un fragmento de su nombre, para cuando ARCA ofrece más de uno de web services y hay que elegir.

Ver como obtener la respuesta de una Automatización

{
  "id": "b7c1d2e3-4f5a-4b6c-9d8e-1f2a3b4c5d6e",
  "status": "complete",
  "data": {
    "tax_id": "20111111112",
    "sales_point": { "number": 4, "display_name": "Factura SDK", "status": "created", "message": null }
  }
}

status es created, o exists si ese número ya estaba dado de alta en ARCA, con el motivo en message.

Delegación

Si el CUIT emite comprobantes para otros usuarios se deben cumplir estos pasos:

  1. El emisor delega el web service de facturación electrónica (wsfe) al CUIT dueño del certificado, desde su clave fiscal en ARCA: cómo delegar un web service.
  2. POST /v1/issuers/:id/delegation con la clave fiscal del dueño del certificado (no la del emisor): Factura SDK acepta la delegación en ARCA y autoriza el certificado para facturar por el emisor.

Requiere que el emisor ya tenga en certificate_id ese certificado, active.

Solicitud
const response = await fetch('https://app.afipsdk.com/api/v1/issuers/<ISSUER_ID>/delegation', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    username: '30715000004',
    password: '<CLAVE_FISCAL>'
  })
});

const { automation_id } = await response.json();

Ver como obtener la respuesta de una Automatización

{
  "id": "a9e2c4b6-1d3f-4a5b-8c7d-2e4f6a8b0c1d",
  "status": "complete",
  "data": {
    "issuer_id": "0f8f3c2a-5b1e-4c7d-9a2e-6d4b8e1f2a3c",
    "certificate_id": "c3a1e7d9-8b2f-4e6a-a1d4-5f7b9c0e2d31",
    "delegation": "accepted",
    "authorization": "created"
  }
}

En el sandbox la delegación es simulada e instantánea; password: "INVALID_PASSWORD" simula una clave fiscal incorrecta.

Verificar un emisor

POST /v1/issuers/:id/verify comprueba que el emisor puede facturar. Factura SDK emite, con su certificado y su punto de venta, una factura de $1 a consumidor final y la nota de crédito que la anula. Si ARCA aprueba las dos, el emisor queda active.

Los dos comprobantes son reales: quedan registrados en ARCA a nombre del emisor y no cuentan para tu plan.

El emisor tiene que tener certificado y punto de venta; si falta alguno, la respuesta es 400.

Solicitud
const response = await fetch('https://app.afipsdk.com/api/v1/issuers/<ISSUER_ID>/verify', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>'
  }
});

const { automation_id } = await response.json();

Ver como obtener la respuesta de una Automatización

{
  "id": "a9e2c4b6-1d3f-4a5b-8c7d-2e4f6a8b0c1d",
  "status": "complete",
  "data": {
    "verified": true,
    "issuer": {
      "id": "0f8f3c2a-5b1e-4c7d-9a2e-6d4b8e1f2a3c",
      "tax_id": "20111111112",
      "status": "active",
      "verified_at": "2026-10-14T14:03:00.000Z"
    },
    "invoice": { "id": "…", "verification": true, "status": "approved", "invoice_type": 6, "sales_point": 1, "number": 1, "total_amount": 1, "cae": "76412345678901", "...": "..." },
    "credit_note": { "id": "…", "verification": true, "status": "approved", "invoice_type": 8, "sales_point": 1, "number": 1, "total_amount": 1, "cae": "76412345678902", "...": "..." }
  }
}

Si alguno de los dos no se aprueba, la automatización termina en error y GET /v1/automations/:id responde 400: step dice cuál falló (invoice o credit_note) y errors por qué.

{
  "id": "a9e2c4b6-1d3f-4a5b-8c7d-2e4f6a8b0c1d",
  "status": "error",
  "data": {
    "statusCode": 400,
    "message": "La factura de verificación no fue aprobada: El numero o fecha del comprobante no se corresponde con el proximo a autorizar. Consultar metodo FECompUltimoAutorizado.",
    "verified": false,
    "step": "invoice",
    "issuer": { "id": "0f8f3c2a-5b1e-4c7d-9a2e-6d4b8e1f2a3c", "tax_id": "20111111112", "status": "pending" },
    "invoice": { "id": "…", "verification": true, "status": "rejected", "invoice_type": 6, "...": "..." },
    "credit_note": null,
    "errors": [
      { "code": "10016", "message": "El numero o fecha del comprobante no se corresponde con el proximo a autorizar. Consultar metodo FECompUltimoAutorizado." }
    ]
  }
}

Las causas típicas son un punto de venta que no es de web services, un certificado que ARCA no tiene autorizado para wsfe, un certificado vencido, o una delegación sin aceptar. Cuando la causa es del certificado, errors[0].code lo dice:

codeQué pasaQué hacer
web_service_not_authorizedEl certificado no está autorizado para wsfe en ARCA.Autorizarlo con POST /v1/certificates/:id/authorize; si es de otro CUIT, la delegación.
certificate_expiredARCA lo rechazó como vencido; quedó expired.Crear un certificado nuevo con POST /v1/issuers/:id/certificate.
certificate_key_mismatchLa clave privada no corresponde al certificado.Subirlo de nuevo con la clave correcta, o crear uno nuevo.
certificate_untrustedARCA no reconoce el certificado como emitido por ella.Crear un certificado nuevo en ARCA.
certificate_invalidARCA no pudo leer el certificado.Crear un certificado nuevo.

Modificar un emisor

PUT /v1/issuers/:id cambia solo los campos que mandás. tax_id no se puede modificar: si cambió, creá otro emisor.

Solicitud
const response = await fetch('https://app.afipsdk.com/api/v1/issuers/<ISSUER_ID>', {
  method: 'PUT',
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    address: 'Av. Siempre Viva 744, CABA',
    sales_point: 2
  })
});

const issuer = await response.json();
CampoDescripción
business_name, address, vat_condition, gross_income, activity_start_dateLos datos fiscales. Los comprobantes ya emitidos no cambian: el PDF conserva los datos del momento de la aprobación.
sales_pointEl punto de venta. null lo borra; el emisor no emite hasta que tenga uno.
certificate_idUn certificado activo. null lo borra; el emisor no emite hasta que tenga uno.
statusactive o inactive, solo en un emisor ya verificado.

Pausar y reactivar

Un emisor inactive no emite. Sirve para detener la facturación a un cliente sin borrarlo.

{
  "status": "inactive"
}

Para reactivarlo, status: "active". No hace falta verificarlo de nuevo.

Borrar un emisor

DELETE /v1/issuers/:id responde 204. El emisor desaparece de la API y del dashboard; sus comprobantes quedan y se siguen pudiendo consultar y listar. El mismo CUIT se puede volver a dar de alta como un emisor nuevo, que arranca pending.

Solicitud
await fetch('https://app.afipsdk.com/api/v1/issuers/<ISSUER_ID>', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>'
  }
});

Consultar y listar

GET /v1/issuers/:id devuelve un emisor; 404 si no existe o fue borrado.

GET /v1/issuers lista los emisores, nunca los borrados, con paginación por cursor.

ParámetroTipoDescripción
tax_idstringCUIT.
certificate_idstringEmisores que firman con ese certificado.
statusstringpending, active o inactive.
limitintegerCantidad por página: por defecto 10, hasta 100. Un valor fuera de rango se ajusta.
cursorstringEl next_cursor de la página anterior, que es el id del último emisor de la página.
Solicitud
const response = await fetch('https://app.afipsdk.com/api/v1/issuers?status=active&limit=50', {
  headers: {
    'Authorization': 'Bearer <ACCESS_TOKEN>'
  }
});

const { data, next_cursor, total_count } = await response.json();
{
  "data": [
    { "id": "0f8f3c2a-5b1e-4c7d-9a2e-6d4b8e1f2a3c", "tax_id": "20111111112", "status": "active", "...": "..." }
  ],
  "next_cursor": null,
  "total_count": 1
}

Errores

HTTPCuándo
400Errores de forma (data_errors); CUIT inválido; certificate_id inexistente o no active; status en un emisor sin verificar; tax_id en un PUT; verificación sin certificado, con uno vencido o revocado, sin punto de venta, o de un emisor que no emite por su condición frente al IVA; delegación sin certificado o con uno del propio CUIT; suscripción vencida o impaga; proyecto que no es de Factura SDK.
401Access token inválido, ausente o revocado.
404El emisor no existe o fue borrado. En el lookup, el CUIT no tiene constancia de inscripción. En GET /v1/automations/:id, la automatización no existe o es de otro proyecto.
409Ya hay un emisor con ese CUIT.
422, 502, 503Solo en el lookup: ARCA rechazó la consulta, falló, o la consulta no está disponible.

El formato de cada código y cómo consultar una automatización están en Errores y respuestas.