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.
Elegí un par y tu destino
Sección titulada «Elegí un par y tu destino»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.
Tres credenciales, tres usos
Sección titulada «Tres credenciales, tres usos»| 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.
Crear desde la API
Sección titulada «Crear desde la API»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.
Evento y firma
Sección titulada «Evento y firma»{ "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/jsonUser-Agent: MonedAPI/2.0Verificá 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.
Pruebas, reintentos y retención
Sección titulada «Pruebas, reintentos y retención»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.
Capacidad y sincronización
Sección titulada «Capacidad y sincronización»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.