Documentación / API / Emisores (merchants)

Subir CSD

POSThttps://api.cfdi.express/v1/merchants/{id}/csdAPI key

Sube el CSD del emisor (.cer y .key en base64 más la contraseña). Se valida, se encripta y se registra con el PAC.

Antes de tocar al PAC validamos localmente: que el .cer sea legible, que esté vigente, que la llave corresponda al certificado, que la contraseña abra la llave y que no estés subiendo una FIEL en lugar de un CSD.

Los archivos se guardan con encriptación de sobre AES-256-GCM. La llave privada nunca se devuelve por la API.

Autenticación
Authorization: Bearer sk_test_... | sk_live_...

Parámetros

Parámetros de ruta

CampoTipoDescripción
idreqstringId del emisor.

Cuerpo (JSON)

CampoTipoDescripción
cerreqstringArchivo .cer (DER) codificado en base64.
keyreqstringArchivo .key (DER, PKCS#8 encriptado) en base64.
passwordreqstringContraseña de la llave privada.

Ejemplos

cURL
curl -X POST https://api.cfdi.express/v1/merchants/mkq2f8v3x1t7p9d4n6c0b5rz/csd \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d "{
    \"cer\": \"$(base64 -w0 CSD_EKU9003173C9.cer)\",
    \"key\": \"$(base64 -w0 CSD_EKU9003173C9.key)\",
    \"password\": \"12345678a\"
  }"
Node.js
import { readFile } from "node:fs/promises";

const [cer, key] = await Promise.all([
  readFile("CSD_EKU9003173C9.cer"),
  readFile("CSD_EKU9003173C9.key"),
]);

const res = await fetch(
  `https://api.cfdi.express/v1/merchants/${merchantId}/csd`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.CFDI_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      cer: cer.toString("base64"),
      key: key.toString("base64"),
      password: "12345678a",
    }),
  },
);

const csd = await res.json();
console.log("Vigente hasta", csd.validTo);

Respuesta

201 Created
{
  "object": "csd",
  "serialNumber": "30001000000500003416",
  "rfc": "EKU9003173C9",
  "validFrom": "2023-05-18T00:00:00.000Z",
  "validTo": "2027-05-18T00:00:00.000Z",
  "status": "active",
  "registeredWithPac": true,
  "updatedAt": "2026-08-18T16:24:51.002Z"
}
400 — CSD inválido
{
  "type": "https://api.cfdi.express/docs/errors/validation_error",
  "title": "Validation error",
  "status": 400,
  "code": "validation_error",
  "detail": "The private key could not be opened with the given password",
  "subcode": "csd_key_unreadable"
}

Errores

StatuscodeCuándo aparece
400validation_errorEl subcode identifica el problema: csd_invalid_cer, csd_expired, csd_not_yet_valid, csd_key_unreadable, csd_key_mismatch, csd_is_fiel o csd_rejected_by_pac.
401unauthorizedFalta el header Authorization o la llave es inválida.
404not_foundEl emisor no existe en tu cuenta.
503pac_unavailableEl PAC no está disponible para registrar el certificado.

Notas

  • El RFC del certificado debe coincidir con el RFC del emisor.
  • Un CSD vencido no se puede subir. Renuévalo en el portal del SAT y usa PUT /v1/merchants/{id}/csd.

Continuar