Ir al contenido

Webhooks

La función está en preparación: la admisión general permanece apagada hasta terminar las mediciones y el despliegue coordinado. La integración operativa fija de ELIT conserva su excepción independiente. Las lecturas públicas siguen disponibles sin cuenta ni key.

Desde tu cuenta podés configurar hasta cinco webhooks, contando los pausados. Cada uno sigue exactamente un par del catálogo y envía POST a una URL HTTPS pública. No tiene nombre: se identifica por par y destino. Los heredados válidos de v1 se conservan pausados, incluso si exceden cinco; no se pueden crear otros hasta quedar debajo del tope.

No se siguen redirects. Localhost, redes privadas, metadata e IPs no globales quedan fuera. En cada intento se validan A/AAAA y se conecta a una IP validada conservando Host, SNI y la verificación del certificado del hostname original.

Credencial Uso
API key de MonedAPI Administrar tus webhooks desde la API. El panel usa tu sesión.
Authorization del receptor Opcional: credencial de tu API, enviada exactamente como la configuraste.
Secreto de firma Uno por webhook, para verificar el origen y los bytes de cada envío.

Rotar/revocar una API key no cambia un webhook de la misma cuenta. URL completa, Authorization y firma se guardan cifradas. GET solo muestra la URL al dueño y si hay credencial; nunca devuelve Authorization ni el secreto. Guardá el secreto al crear o rotar: se muestra una sola vez.

Ventana de terminal
curl https://monedapi.ar/api/v2/webhooks \
-H 'Authorization: Bearer <API_KEY_MONEDAPI>' \
-H 'Content-Type: application/json' \
-d '{
"operationId": "12345678-1234-1234-1234-123456789abc",
"url": "https://tu-api.example/webhooks",
"currency": "USD",
"origin": "BNA",
"enabled": true,
"receiverAuthorization": "Bearer <CREDENCIAL_DE_TU_API>"
}'

operationId es un UUID nuevo por alta. Si se pierde la respuesta, consultá el listado y buscá la operación. Repetirla no duplica la suscripción ni vuelve a emitir el secreto: para reemplazar uno perdido, rotalo explícitamente. Las mutaciones de un recurso exigen su version vigente; una edición concurrente o un envío en vuelo puede producir 409.

Método y ruta Resultado
GET /api/v2/webhooks Listado propio, destino enmascarado.
POST /api/v2/webhooks 201 con suscripción y secreto; 200 al reconciliar.
GET /api/v2/webhooks/{id} Configuración propia sin credenciales.
PATCH /api/v2/webhooks/{id} Edición con version; solicita sincronización.
DELETE /api/v2/webhooks/{id} Borrado con version.
POST /api/v2/webhooks/{id}/rotate-secret Rotación con version, nuevo secreto.
POST /api/v2/webhooks/{id}/test Cuerpo {}; 202 con ID de una prueba pendiente.
GET /api/v2/webhooks/deliveries Hasta 50 propias, filtros y cursor.

Podés usar x-api-key en lugar de Bearer. Una cookie no sustituye la key en estas rutas. No aceptamos credenciales en query. Historial admite solo webhookId, deliveryId, status, limit (1–50) y cursor devuelto por la página anterior. Un cursor ajeno o podado da 404. La referencia de la API y OpenAPI 2.4.0 detallan los cuerpos.

{
"event": "rate.updated",
"currency": "USD",
"origin": "BLUE",
"buy": 1375,
"sell": 1395,
"prevBuy": 1370,
"prevSell": 1385,
"changePct": 0.72,
"valueType": "money",
"updatedAt": "2026-10-06T14:32:00.000Z",
"timestamp": "2026-10-06T14:32:00.000Z"
}

changePct compara venta; vale cero si la anterior es cero. Índices usan points o coefficient, con compra y venta iguales. Discord se reconoce por hostname/path exactos y recibe un embed con las unidades del par. La firma cubre ese cuerpo final.

Todos los envíos generales, incluidas pruebas y sincronizaciones, llevan:

X-MonedAPI-Delivery-Id: <ID estable>
X-MonedAPI-Webhook-Id: <ID de la suscripción>
X-MonedAPI-Timestamp: <Unix en segundos del intento>
X-MonedAPI-Signature: sha256=<HMAC-SHA256 hexadecimal>
Content-Type: application/json
User-Agent: MonedAPI/2.0

Verificá HMAC-SHA256(secreto, timestamp + "." + cuerpo_crudo), comparando en tiempo constante. El secreto hexadecimal se usa como texto UTF-8, sin decodificarlo a bytes. Conservá los bytes crudos recibidos antes de parsear JSON; reserializarlo puede cambiar la firma. Comprobá una ventana de tiempo corta y deduplicá X-MonedAPI-Delivery-Id. Cada intento tiene timestamp y firma nuevos, pero conserva ID y cuerpo.

La prueba es manual.trigger, con isManual: true, anteriores iguales al vigente y cambio cero. 202 significa aceptada en cola; recién delivered acredita un 2xx del receptor. Sin cotización devuelve 409 quote_unavailable; sin capacidad, 503 y Retry-After.

Cada entrega tiene hasta cuatro intentos, deadline total de diez segundos y esperas base de 30 segundos, cinco minutos y treinta minutos, con jitter. Solo 2xx confirma. No se promete exactamente una vez ni orden de procesamiento interno del receptor. El orden de emisión es por suscripción; un receptor en backoff no bloquea los otros.

Diez intentos automáticos fallidos seguidos pausan la suscripción y preparan un único aviso por episodio. Un éxito automático reinicia la secuencia. Las pruebas no la incrementan ni reinician. Revisá el receptor antes de activar; recibir un correo no activa webhooks.

El historial incluye pending, sending, failed, delivered, dead y cancelled, sin HTML, credenciales ni tokens del receptor. Se poda a siete días desde la creación, incluso con envíos apagados. Una entrega vencida puede desaparecer sin haber sido recibida.

La capacidad se reserva antes de aceptar eventos. Al agotarse, se suspende la generación nueva; las entregas aceptadas siguen su política acotada. Pueden omitirse cambios intermedios. Al recuperar margen, se sincroniza el vigente después de resolver la cola anterior: rate.updated, anteriores iguales, variación cero y X-MonedAPI-Delivery-Type: sync. Activar también solicita esta sincronización. updatedAt conserva el tiempo real del dato. Pausas manuales o por fallos requieren activación del dueño.

La RPi es el emisor principal. Tras 90 segundos sin su señal propia, el cron puede solicitar un respaldo Node acotado en GitHub Actions, dentro de su cuota compartida. La espera del runner no garantiza un tiempo de arranque o entrega. D1 conserva reclamos y resultados de ambos. ELIT es un destino de sistema fijo, sin cuenta, HMAC, Authorization, pausa automática ni correos generales; esa excepción no está disponible para webhooks de usuarios.