Catálogos
Productos y servicios
Tu catálogo con claves del SAT e impuestos por default, para no repetirlos en cada timbrado.
Registrar un producto es opcional: puedes mandar cada concepto completo al timbrar. Pero un catálogo te ahorra repetir las claves del SAT en cada factura y —más importante— evita que un typo en una clave de 8 dígitos se cuele en un CFDI.
Con un producto registrado, un concepto se reduce a:
{ "productId": "clxp01…", "quantity": 2 }
Listar y buscar
GET /api/authenticated/{org}/products
Scope: products.read
| Parámetro | Tipo | Descripción |
|---|---|---|
q | string | Busca en descripción y clave del SAT. |
limit | número | 1–500. Default 50. |
cursor | cuid | Paginación. |
{
"items": [
{
"id": "clxp01…",
"claveProdServ": "81111500",
"claveUnidad": "E48",
"description": "Servicios de desarrollo de software",
"unitPrice": "1500.00",
"iva": "0.160000",
"ivaExento": false,
"ieps": null,
"iepsCuota": null,
"isr": null,
"ivaRet": null,
"iepsRet": null,
"objetoImp": "02",
"noIdentificacion": "DEV-001",
"createdAt": "2026-02-02T10:00:00.000Z"
}
],
"nextCursor": null
}
Crear
POST /api/authenticated/{org}/products
Scope: products.create
| Campo | Requerido | Reglas |
|---|---|---|
claveProdServ | sí | 8 dígitos del catálogo c_ClaveProdServ. |
claveUnidad | sí | 2–3 caracteres de c_ClaveUnidad (p. ej. E48 servicio, H87 pieza, KGM kilogramo). |
description | sí | 3–1000 caracteres. Es lo que se imprime en el CFDI. |
unitPrice | sí | Precio unitario sin impuestos. |
code | no | Tu propio SKU o referencia del ERP. Único dentro de la organización; es la llave que usa upsert. |
iva | no | Tasa decimal: 0, 0.08 o 0.16. |
ivaExento | no | Booleano. Excluyente con una tasa de iva distinta de cero. |
ieps | no | Tasa decimal de IEPS. |
iepsCuota | no | IEPS de cuota, en pesos por unidad. Excluyente con ieps. |
isr, ivaRet, iepsRet | no | Tasas de retención por default. |
objetoImp | no | Clave de c_ObjetoImp (01–08). Si la omites, se deriva: 02 si el concepto lleva impuestos, 01 si no. |
noIdentificacion | no | Número de parte / SKU que se imprime en el CFDI. Máx. 100 caracteres. |
fraccionArancelaria, claveUnidadAduana | no | Datos aduaneros, solo para exportación. |
upsert | no | Ver abajo. |
curl -s -X POST "$FACTY_HOST/api/authenticated/$FACTY_ORG/products" \
-H "X-API-Key: $FACTY_KEY" -H "Content-Type: application/json" \
-d '{
"code": "DEV-001",
"claveProdServ": "81111500",
"claveUnidad": "E48",
"description": "Servicios de desarrollo de software",
"unitPrice": 1500,
"iva": 0.16
}' | jq
upsert con tu propio code
Igual que en clientes, "upsert": true convierte un code ya existente en el
caso de éxito (200, created: false) en vez de crear un duplicado. Requiere que
mandes code: sin él no hay contra qué empatar.
Tampoco sobrescribe el registro existente. Para empujar cambios de precio o de
clave, usa PATCH /products/{productId}.
Encontrar las claves del SAT
No adivines las claves. Hay endpoints de búsqueda:
# Clave de producto/servicio (~52,000 entradas, búsqueda por texto)
curl -s "$FACTY_HOST/api/authenticated/catalogs/clave-prod-serv?q=software" \
-H "X-API-Key: $FACTY_KEY" | jq
# Clave de unidad
curl -s "$FACTY_HOST/api/authenticated/catalogs/clave-unidad?q=servicio" \
-H "X-API-Key: $FACTY_KEY" | jq
Ver Catálogos del SAT.
Herencia: producto → concepto
Al timbrar, cada campo del concepto que omites se hereda del producto. Cada campo que mandas gana:
{
"items": [
{ "productId": "clxp01…", "quantity": 3 },
{ "productId": "clxp01…", "quantity": 1, "unitPrice": 1200, "descuento": 0.10 }
]
}
El primer concepto usa el precio y el IVA del producto. El segundo usa un precio negociado y le aplica 10% de descuento, conservando el IVA del catálogo.
Si no mandas productId, el concepto tiene que traer al menos claveProdServ,
claveUnidad, description y unitPrice, o el timbrado responde 422.