cURL y shell
Todo AlchemyCode API se puede operar con curl. Esta guía cubre autenticación, alta de
empresa, e.firma multipart, consulta con polling, descarga de archivos firmados y diagnóstico de errores.
Preparar el entorno
Shell
export ALCHEMY_API_KEY="ck_live_7f3a91c2m4p8q1w7x5n3v9b6t0"
export API="https://api.434alchemycode.com/v1"
export COMPANY_ID="9b2f5c1e-7a3d-4f8b-9c21-6d4e8a0b5f17"
# Nunca pegues la llave directo en la línea de comandos: queda en el historial.
# Usa una variable de entorno o un archivo con permisos 600 leído por --config.
Endpoints de servicio
| Ruta | Servicio | Modo |
|---|---|---|
/v1/sat/constancias | Constancia SAT | Asíncrono |
/v1/sat/opiniones | Opinión 32-D | Asíncrono |
/v1/sat/domicilios | Domicilio fiscal | Asíncrono |
/v1/imss/buzones | Buzón IMSS | Asíncrono |
/v1/imss/opiniones | Opinión IMSS | Asíncrono |
/v1/infonavit/opiniones | Opinión Infonavit | Asíncrono |
/v1/sat/articulo-69b | Artículo 69-B | Síncrono |
/v1/captcha/resoluciones | CAPTCHA | Síncrono |
Alta de empresa
Shell
curl -sS -X POST "$API/companies" \
-H "Authorization: Bearer $ALCHEMY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"rfc": "OMX2503255F9",
"legal_name": "OMNICONMX, S.A. de C.V.",
"tax_regime": "601",
"external_ref": "OMNICOM-001"
}' | python3 -m json.tool
Carga de e.firma
Shell
curl -sS -X POST "$API/companies/$COMPANY_ID/credentials/sat" \
-H "Authorization: Bearer $ALCHEMY_API_KEY" \
-F "cer=@./omnicom.cer;type=application/x-x509-ca-cert" \
-F "key=@./omnicom.key;type=application/octet-stream" \
-F "password=$FIEL_PASSWORD" | python3 -m json.tool
No agregues
-H "Content-Type: multipart/form-data": cURL debe generar el boundary. Si lo fijas a mano, el servidor no puede separar las partes.Consulta con polling
Este script no depende de jq: usa python3 para leer el JSON. Funciona en macOS y Linux.
Shellconsulta.sh
#!/usr/bin/env bash
set -euo pipefail
: "${ALCHEMY_API_KEY:?Falta ALCHEMY_API_KEY}"
API="https://api.434alchemycode.com/v1"
COMPANY_ID="9b2f5c1e-7a3d-4f8b-9c21-6d4e8a0b5f17"
job=$(curl -sS -X POST "$API/sat/constancias" \
-H "Authorization: Bearer $ALCHEMY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen | tr '[:upper:]' '[:lower:]')" \
-d "{\"company_id\":\"$COMPANY_ID\",\"include_pdf\":true}")
job_id=$(printf '%s' "$job" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')
echo "Job: $job_id"
for attempt in $(seq 1 60); do
payload=$(curl -sS "$API/jobs/$job_id" -H "Authorization: Bearer $ALCHEMY_API_KEY")
state=$(printf '%s' "$payload" | python3 -c 'import json,sys; print(json.load(sys.stdin)["status"])')
echo "Intento $attempt: $state"
case "$state" in
succeeded)
printf '%s' "$payload" > "job-$job_id.json"
break
;;
failed|canceled|expired)
printf '%s\n' "$payload" >&2
exit 1
;;
esac
sleep 2
done
# Descarga el primer archivo (URL firmada, expira en 15 min)
file_url=$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["files"][0]["url"])' "job-$job_id.json")
curl -sS "https://api.434alchemycode.com$file_url" -o constancia.pdf
echo "PDF: constancia.pdf ($(wc -c < constancia.pdf) bytes)"
Consulta con wait=true
Shell
curl -sS -X POST "$API/sat/opiniones" \
-H "Authorization: Bearer $ALCHEMY_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"company_id\":\"$COMPANY_ID\",\"wait\":true}" \
-w '\nHTTP %{{http_code}} en %{{time_total}} s\n'
Si el job no termina en 25 segundos, verás HTTP 202 con el job en curso. Vuelve a consultarlo por
/jobs/{id}.
Diagnóstico de errores
Shell
# -i muestra status y cabeceras; el error viene como application/problem+json
curl -i -sS -X POST "$API/sat/constancias" \
-H "Authorization: Bearer $ALCHEMY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"company_id": "no-es-un-uuid"}'
# Filtra sólo el código y el request_id (sin jq)
curl -sS "$API/me" -H "Authorization: Bearer $ALCHEMY_API_KEY" \
| python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["plan"]["name"], d["quota"]["used"], "/", d["quota"]["quota"])'
HTTP
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
X-Request-Id: req_2b7e9d1c4a6f8035
{
"code": "VALIDATION_ERROR",
"detail": "Revisa los campos marcados en `errors`.",
"request_id": "req_2b7e9d1c4a6f8035",
"retryable": false,
"errors": [{"field": "company_id", "code": "UUID_PARSING", "message": "Debe ser un UUID válido."}]
}Buenas prácticas con cURL
- Usa
-sS: silencio en progreso, pero errores de red visibles. - No pongas la llave en el comando: queda en
~/.bash_historyy enps. - Guarda el JSON del job en un archivo antes de descargar archivos.
- Usa
--connect-timeout 10 --max-time 60en scripts desatendidos. - Para lotes de 69-B, envía un archivo con
--data-binary @lote.json. - Verifica el status con
-w '%{http_code}'; no confíes sólo en la ausencia de error de cURL.