{"openapi":"3.1.0","info":{"title":"CoatiPay API","version":"0.1","description":"Pagos en USDC sin custodia y sin gas para quien paga. Todos los importes, en unidades base de USDC (6 decimales). Cada error trae un `code` del catálogo y su referencia en `doc_url`."},"servers":[{"url":"https://api.coatipay.com/v1"}],"tags":[{"name":"Payment intents"},{"name":"Webhooks"},{"name":"Nodes"},{"name":"x402"},{"name":"Checkout","description":"Público: sin clave, con el `client_secret` del cobro."}],"security":[{"claveApi":[]}],"paths":{"/payment_intents":{"post":{"operationId":"createPaymentIntent","tags":["Payment intents"],"summary":"Crear un cobro","description":"Con `Idempotency-Key`, repetir la misma petición devuelve el mismo cobro (200); la misma clave con otros parámetros es 409 `idempotency_key_reused`.","security":[{"claveApi":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opcional. Identifica este cobro para poder reintentar sin duplicarlo (p. ej. el id de la orden).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePaymentIntent"}}}},"responses":{"200":{"description":"La misma petición con la misma `Idempotency-Key`: el cobro que ya existía.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntent"}}}},"201":{"description":"Cobro creado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntent"}}}},"400":{"description":"`invalid_request`, `amount_below_minimum`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`idempotency_key_reused`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listPaymentIntents","tags":["Payment intents"],"summary":"Listar cobros","security":[{"claveApi":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Cuántos por página, hasta 100 (más se reduce a 100).","schema":{"default":10,"type":"integer","minimum":1}},{"name":"starting_after","in":"query","required":false,"description":"Id del último cobro de la página anterior.","schema":{"type":"string"}}],"responses":{"200":{"description":"Una página de cobros.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntentList"}}}},"400":{"description":"`invalid_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/payment_intents/{id}":{"get":{"operationId":"retrievePaymentIntent","tags":["Payment intents"],"summary":"Consultar un cobro","security":[{"claveApi":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Id del cobro (`pi_…`).","schema":{"type":"string"}}],"responses":{"200":{"description":"El cobro.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntent"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`intent_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/payment_intents/{id}/cancel":{"post":{"operationId":"cancelPaymentIntent","tags":["Payment intents"],"summary":"Cancelar un cobro","description":"Solo un cobro `created` sin un pago en camino. Si un nodeit ya reclamó su autorización, 409 `payment_in_progress`: ese pago puede liquidarse igual.","security":[{"claveApi":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Id del cobro (`pi_…`).","schema":{"type":"string"}}],"responses":{"200":{"description":"El cobro, ya `cancelled`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentIntent"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`intent_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`intent_already_settled`, `payment_in_progress`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/payment_intents/{id}/authorize":{"post":{"operationId":"authorizePaymentIntent","tags":["Payment intents"],"summary":"Enviar la autorización del pagador","description":"Valida la firma ERC-3009 contra la cadena y la deja en cola para que un nodeit la liquide. El pago se confirma con el webhook `payment_intent.settled`.","security":[{"claveApi":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Id del cobro (`pi_…`).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Erc3009Authorization"}}}},"responses":{"200":{"description":"Autorización en cola.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizationQueued"}}}},"400":{"description":"`invalid_request`, `intent_not_payable`, `authorization_expired`, `authorization_not_yet_valid`, `authorization_not_bound_to_intent`, `invalid_signer`, `unsupported_chain`, `unsupported_signature`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`intent_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`nonce_already_used`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"`signature_unverifiable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/payment_intents/batch/authorize":{"post":{"operationId":"authorizePaymentIntentsBatch","tags":["Payment intents"],"summary":"Enviar varias autorizaciones","description":"Cada autorización se valida por separado; las que no pasan salen como `rejected` con su código.","security":[{"claveApi":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchAuthorizeRequest"}}}},"responses":{"200":{"description":"Un resultado por autorización.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchAuthorizeResult"}}}},"400":{"description":"`invalid_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"post":{"operationId":"createWebhookEndpoint","tags":["Webhooks"],"summary":"Registrar un endpoint","security":[{"claveApi":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookEndpoint"}}}},"responses":{"201":{"description":"Endpoint registrado, con su secreto.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreated"}}}},"400":{"description":"`invalid_request`, `invalid_webhook_url`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listWebhookEndpoints","tags":["Webhooks"],"summary":"Listar endpoints","security":[{"claveApi":[]}],"responses":{"200":{"description":"Los endpoints activos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointList"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}":{"delete":{"operationId":"deleteWebhookEndpoint","tags":["Webhooks"],"summary":"Dar de baja un endpoint","description":"Idempotente: 204 también si ya no existía o no es de este comercio.","security":[{"claveApi":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Id del endpoint (`we_…`).","schema":{"type":"string"}}],"responses":{"204":{"description":"Dado de baja."},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}/rotate_secret":{"post":{"operationId":"rotateWebhookSecret","tags":["Webhooks"],"summary":"Rotar el secreto de un endpoint","description":"Devuelve un secreto nuevo. El anterior sigue firmando junto a él durante `keep_previous_for` segundos (24 h por defecto), para cambiarlo en tu servidor sin perder entregas; con `0` deja de valer en el acto. Nunca conviven más de dos: rotar otra vez dentro de la ventana retira el más antiguo.","security":[{"claveApi":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Id del endpoint (`we_…`).","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateWebhookSecret"}}}},"responses":{"200":{"description":"El endpoint, con su secreto nuevo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSecretRotated"}}}},"400":{"description":"`invalid_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/dead_letters":{"get":{"operationId":"listDeadLetters","tags":["Webhooks"],"summary":"Listar entregas fallidas (DLQ)","security":[{"claveApi":[]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Cuántas por página, hasta 100.","schema":{"default":20,"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Una página de entregas fallidas.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeadLetterList"}}}},"400":{"description":"`invalid_request`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/dead_letters/{id}/replay":{"post":{"operationId":"replayDeadLetter","tags":["Webhooks"],"summary":"Reenviar una entrega fallida","description":"El mismo evento, con el mismo id, al mismo endpoint y con los reintentos a cero.","security":[{"claveApi":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Id de la entrega fallida (`dlq_…`).","schema":{"type":"string"}}],"responses":{"202":{"description":"Reenvío en cola.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeadLetter"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"`insufficient_permissions`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`webhook_endpoint_deleted`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/nodes":{"get":{"operationId":"listNodes","tags":["Nodes"],"summary":"Listar nodeits activos","security":[{"claveApi":[]}],"responses":{"200":{"description":"Los nodeits activos del registro on-chain.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeList"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"`node_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/nodes/{operator}":{"get":{"operationId":"retrieveNode","tags":["Nodes"],"summary":"Consultar un nodeit","security":[{"claveApi":[]}],"parameters":[{"name":"operator","in":"path","required":true,"description":"Dirección del operador (0x…).","schema":{"type":"string"}}],"responses":{"200":{"description":"El nodeit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Node"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`node_not_registered`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"`node_unavailable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/x402/verify":{"post":{"operationId":"verifyX402Payment","tags":["x402"],"summary":"Verificar un pago x402","description":"Comprueba en la cadena la transacción de la cabecera `X-PAYMENT`. Cada transacción vale una sola vez.","security":[{"claveApi":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402VerifyRequest"}}}},"responses":{"200":{"description":"Pago verificado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/X402Verification"}}}},"400":{"description":"`invalid_request`, `invalid_payment_payload`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"`invalid_api_key`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"`chain_verification_failed`, `insufficient_payment`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`x402_replay`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/checkout/{id}":{"get":{"operationId":"retrieveCheckout","tags":["Checkout"],"summary":"Ver un cobro para pagarlo","description":"Sin clave: con el `client_secret` del cobro. Lo usa el checkout alojado.","security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"Id del cobro (`pi_…`).","schema":{"type":"string"}},{"name":"client_secret","in":"query","required":true,"description":"El `client_secret` del cobro.","schema":{"type":"string"}}],"responses":{"200":{"description":"Lo necesario para firmar el pago.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutView"}}}},"404":{"description":"`intent_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/checkout/{id}/authorize":{"post":{"operationId":"authorizeCheckout","tags":["Checkout"],"summary":"Pagar desde el checkout","description":"La autorización del pagador, con el `client_secret` del cobro. Se valida como en `authorizePaymentIntent`.","security":[],"parameters":[{"name":"id","in":"path","required":true,"description":"Id del cobro (`pi_…`).","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutAuthorizeRequest"}}}},"responses":{"200":{"description":"Autorización en cola.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutAuthorizationQueued"}}}},"400":{"description":"`invalid_request`, `intent_not_payable`, `authorization_expired`, `authorization_not_yet_valid`, `authorization_not_bound_to_intent`, `invalid_signer`, `unsupported_chain`, `unsupported_signature`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"`intent_not_found`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`nonce_already_used`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`rate_limited`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"`internal_error`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"`signature_unverifiable`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"payment_intent.created":{"post":{"summary":"payment_intent.created","parameters":[{"name":"X-Signature","in":"header","required":true,"description":"`t=<timestamp>,v1=<hmac_hex>`: HMAC-SHA256 con el secreto del endpoint sobre `<timestamp>.<cuerpo>`.","schema":{"type":"string"}},{"name":"X-Webhook-Id","in":"header","required":true,"description":"El endpoint que lo recibe.","schema":{"type":"string"}},{"name":"X-Delivery-Id","in":"header","required":true,"description":"Este evento en este endpoint: no cambia al reintentar ni al reenviar.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta se reintenta (6 intentos en ~17 h) y después va al DLQ."}}}},"payment_intent.settled":{"post":{"summary":"payment_intent.settled","parameters":[{"name":"X-Signature","in":"header","required":true,"description":"`t=<timestamp>,v1=<hmac_hex>`: HMAC-SHA256 con el secreto del endpoint sobre `<timestamp>.<cuerpo>`.","schema":{"type":"string"}},{"name":"X-Webhook-Id","in":"header","required":true,"description":"El endpoint que lo recibe.","schema":{"type":"string"}},{"name":"X-Delivery-Id","in":"header","required":true,"description":"Este evento en este endpoint: no cambia al reintentar ni al reenviar.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta se reintenta (6 intentos en ~17 h) y después va al DLQ."}}}},"payment_intent.expired":{"post":{"summary":"payment_intent.expired","parameters":[{"name":"X-Signature","in":"header","required":true,"description":"`t=<timestamp>,v1=<hmac_hex>`: HMAC-SHA256 con el secreto del endpoint sobre `<timestamp>.<cuerpo>`.","schema":{"type":"string"}},{"name":"X-Webhook-Id","in":"header","required":true,"description":"El endpoint que lo recibe.","schema":{"type":"string"}},{"name":"X-Delivery-Id","in":"header","required":true,"description":"Este evento en este endpoint: no cambia al reintentar ni al reenviar.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta se reintenta (6 intentos en ~17 h) y después va al DLQ."}}}},"payment_intent.cancelled":{"post":{"summary":"payment_intent.cancelled","parameters":[{"name":"X-Signature","in":"header","required":true,"description":"`t=<timestamp>,v1=<hmac_hex>`: HMAC-SHA256 con el secreto del endpoint sobre `<timestamp>.<cuerpo>`.","schema":{"type":"string"}},{"name":"X-Webhook-Id","in":"header","required":true,"description":"El endpoint que lo recibe.","schema":{"type":"string"}},{"name":"X-Delivery-Id","in":"header","required":true,"description":"Este evento en este endpoint: no cambia al reintentar ni al reenviar.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"2XX":{"description":"Recibido. Cualquier otra respuesta se reintenta (6 intentos en ~17 h) y después va al DLQ."}}}}},"components":{"securitySchemes":{"claveApi":{"type":"http","scheme":"bearer","description":"`sk_live_…` en el servidor, para todo; `pk_live_…` para leer."}},"schemas":{"AuthorizationQueued":{"type":"object","properties":{"intent_id":{"type":"string"},"status":{"type":"string","const":"queued"},"estimated_settlement_at":{"type":"null"}},"required":["intent_id","status","estimated_settlement_at"],"additionalProperties":false,"description":"La firma es válida y queda en cola para que un nodeit la liquide. El pago se confirma con `payment_intent.settled`."},"BatchAuthorizeRequest":{"type":"object","properties":{"items":{"minItems":1,"maxItems":50,"type":"array","items":{"type":"object","properties":{"intent_id":{"type":"string","minLength":1},"authorization":{"$ref":"#/components/schemas/Erc3009Authorization"}},"required":["intent_id","authorization"]}}},"required":["items"],"description":"Hasta 50 autorizaciones, cada una para su cobro."},"BatchAuthorizeResult":{"type":"object","properties":{"results":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"intent_id":{"type":"string"},"status":{"type":"string","const":"queued"}},"required":["intent_id","status"],"additionalProperties":false},{"type":"object","properties":{"intent_id":{"type":"string"},"status":{"type":"string","const":"rejected"},"reason":{"type":"string","enum":["invalid_api_key","insufficient_permissions","forbidden","session_required","invalid_session","invalid_token","invalid_request","amount_below_minimum","invalid_webhook_url","invalid_payment_payload","authorization_expired","authorization_not_yet_valid","authorization_not_bound_to_intent","invalid_signer","unsupported_chain","unsupported_signature","intent_not_found","not_found","node_not_registered","authorization_not_claimed","intent_already_settled","payment_in_progress","intent_not_payable","nonce_already_used","idempotency_key_reused","webhook_endpoint_deleted","email_taken","already_reviewed","chain_verification_failed","insufficient_payment","x402_replay","node_unavailable","rate_limited","signature_unverifiable","internal_error"],"description":"El código que habría devuelto la autorización individual."}},"required":["intent_id","status","reason"],"additionalProperties":false}]}},"queued":{"type":"integer"},"rejected":{"type":"integer"}},"required":["results","queued","rejected"],"additionalProperties":false,"description":"Un resultado por autorización, en el mismo orden."},"CheckoutAuthorizationQueued":{"type":"object","properties":{"intent_id":{"type":"string"},"status":{"type":"string","const":"queued"}},"required":["intent_id","status"],"additionalProperties":false,"description":"La firma es válida y queda en cola para liquidarse."},"CheckoutAuthorizeRequest":{"type":"object","properties":{"client_secret":{"type":"string","minLength":1,"maxLength":128,"description":"El `client_secret` del cobro: el id solo no basta para pagarlo."},"payer":{"description":"La cartera que paga.","type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"valid_after":{"type":"string","pattern":"^\\d+$","description":"Segundos, en texto decimal. Los SDK firman con `0`."},"valid_before":{"type":"string","pattern":"^\\d+$","description":"Segundos, en texto decimal: a partir de ahí la firma no vale."},"nonce":{"description":"El id on-chain del cobro: `keccak256` de su id. Ata la firma a este cobro.","type":"string","pattern":"^0x[a-fA-F0-9]{64}$"},"signature":{"type":"string","pattern":"^0x([a-fA-F0-9]{2})+$","description":"EIP-712. 65 bytes de una cartera normal; más de un monedero inteligente (ERC-1271 / ERC-6492)."}},"required":["client_secret","payer","valid_after","valid_before","nonce","signature"],"description":"La autorización del pagador, con el `client_secret` del cobro."},"CheckoutView":{"type":"object","properties":{"id":{"type":"string"},"amount":{"type":"integer"},"currency":{"type":"string","enum":["usdc","btc"]},"status":{"type":"string","enum":["created","settled","expired","cancelled"]},"tx_hash":{"anyOf":[{"type":"string"},{"type":"null"}]},"payer_address":{"anyOf":[{"type":"string"},{"type":"null"}]},"merchant_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"chain":{"type":"string","enum":["base","base-sepolia"],"description":"La red contra la que hay que firmar."},"settlement_hub":{"type":"string","description":"El `to` de la autorización ERC-3009."},"last_rejection":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","enum":["insufficient_balance","authorization_expired","invalid_signature","other"],"description":"`insufficient_balance`: la wallet no tiene USDC suficiente. `authorization_expired`: la firma caducó antes de liquidarse. `invalid_signature`: la firma no es de esa wallet para este pago. `other`: cualquier otro motivo."},"at":{"type":"integer","description":"Cuándo se envió esa autorización (segundos)."}},"required":["reason","at"],"additionalProperties":false},{"type":"null"}],"description":"Si el último intento de pago de un cobro aún por pagar se rechazó, por qué. Se puede volver a firmar."}},"required":["id","amount","currency","status","tx_hash","payer_address","merchant_name","chain","settlement_hub","last_rejection"],"additionalProperties":false,"description":"Lo mínimo para pagar un cobro: sin metadata, sin datos del comercio, sin secreto."},"CreatePaymentIntent":{"type":"object","properties":{"amount":{"type":"integer","exclusiveMinimum":0,"description":"En unidades base de USDC (6 decimales): 1.50 USDC = `1500000`."},"currency":{"type":"string","enum":["usdc","btc"]},"chain":{"default":"base","description":"Etiqueta: la red la fija la API.","type":"string","enum":["base","polygon","auto"]},"metadata":{"default":{},"description":"Tus datos (p. ej. el id de la orden). Vuelven en el cobro y en sus webhooks.","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"expires_in":{"default":1800,"description":"Segundos hasta que vence.","type":"integer","exclusiveMinimum":0}},"required":["amount","currency"],"description":"Un cobro nuevo."},"CreateWebhookEndpoint":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"HTTPS y pública: no se aceptan `http://`, `localhost` ni direcciones internas."},"events":{"minItems":1,"type":"array","items":{"type":"string","enum":["payment_intent.created","payment_intent.settled","payment_intent.expired","payment_intent.cancelled"]}}},"required":["url","events"],"description":"Un endpoint y los eventos que quiere recibir."},"DeadLetter":{"type":"object","properties":{"id":{"type":"string"},"endpoint_id":{"type":"string"},"endpoint_url":{"type":"string"},"event_id":{"type":"string"},"event_type":{"type":"string"},"delivery_id":{"type":"string","description":"El de la cabecera `X-Delivery-Id` de esa entrega."},"attempts":{"type":"integer"},"last_error":{"anyOf":[{"type":"string"},{"type":"null"}]},"last_attempted_at":{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},"created_at":{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},"replayed_at":{"anyOf":[{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},{"type":"null"}],"description":"Cuándo se reenvió por última vez."},"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"El cuerpo firmado del evento, tal como se envió."}},"required":["id","endpoint_id","endpoint_url","event_id","event_type","delivery_id","attempts","last_error","last_attempted_at","created_at","replayed_at","payload"],"additionalProperties":false,"description":"Una entrega que no llegó a su endpoint: casi siempre porque agotó sus reintentos (6, a lo largo de ~17 h); `last_error` dice por qué. Se puede reenviar con el mismo id de evento."},"DeadLetterList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DeadLetter"}},"has_more":{"type":"boolean"}},"required":["data","has_more"],"additionalProperties":false,"description":"De la más reciente a la más antigua."},"Erc3009Authorization":{"type":"object","properties":{"payer":{"description":"La cartera que paga.","type":"string","pattern":"^0x[a-fA-F0-9]{40}$"},"valid_after":{"type":"string","pattern":"^\\d+$","description":"Segundos, en texto decimal. Los SDK firman con `0`."},"valid_before":{"type":"string","pattern":"^\\d+$","description":"Segundos, en texto decimal: a partir de ahí la firma no vale."},"nonce":{"description":"El id on-chain del cobro: `keccak256` de su id. Ata la firma a este cobro.","type":"string","pattern":"^0x[a-fA-F0-9]{64}$"},"signature":{"type":"string","pattern":"^0x([a-fA-F0-9]{2})+$","description":"EIP-712. 65 bytes de una cartera normal; más de un monedero inteligente (ERC-1271 / ERC-6492)."}},"required":["payer","valid_after","valid_before","nonce","signature"],"description":"Una autorización ERC-3009 `ReceiveWithAuthorization` firmada por el pagador, con el dominio EIP-712 del USDC de la red y el hub como `to`."},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_api_key","insufficient_permissions","forbidden","session_required","invalid_session","invalid_token","invalid_request","amount_below_minimum","invalid_webhook_url","invalid_payment_payload","authorization_expired","authorization_not_yet_valid","authorization_not_bound_to_intent","invalid_signer","unsupported_chain","unsupported_signature","intent_not_found","not_found","node_not_registered","authorization_not_claimed","intent_already_settled","payment_in_progress","intent_not_payable","nonce_already_used","idempotency_key_reused","webhook_endpoint_deleted","email_taken","already_reviewed","chain_verification_failed","insufficient_payment","x402_replay","node_unavailable","rate_limited","signature_unverifiable","internal_error"]},"message":{"type":"string"},"param":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"El campo que falla, cuando lo hay (`amount`, `events.0`, `Idempotency-Key`…)."},"doc_url":{"type":"string","format":"uri","description":"La referencia del código: `https://coatipay.com/docs/errors/<code>`."}},"required":["code","message","param","doc_url"],"additionalProperties":false}},"required":["error"],"additionalProperties":false,"description":"Toda respuesta de error. `code` es un código del catálogo, siempre con el mismo estado HTTP; su referencia está en `doc_url`."},"Node":{"type":"object","properties":{"operator":{"type":"string"},"endpoint":{"type":"string"},"active":{"type":"boolean"},"registered_at":{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},"stake":{"type":"string","description":"Stake vinculado, en unidades base de USDC (en texto: puede pasar de 2^53)."},"pending_withdrawal":{"type":"string","description":"Stake en el periodo de retirada de 7 días."},"min_stake":{"type":"string"},"online":{"type":"boolean","description":"¿Respondió a `GET /health`?"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Reputación. Aún sin motor de reputación: `null`."},"is_bootstrap":{"type":"boolean"}},"required":["operator","endpoint","active","registered_at","stake","pending_withdrawal","min_stake","online","score","is_bootstrap"],"additionalProperties":false,"description":"Un nodeit del registro on-chain."},"NodeList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Node"}},"total":{"type":"integer"}},"required":["data","total"],"additionalProperties":false,"description":"Los nodeits activos."},"PaymentIntent":{"type":"object","properties":{"id":{"type":"string"},"merchant_id":{"type":"string"},"amount":{"type":"integer","description":"En unidades base de USDC."},"currency":{"type":"string","enum":["usdc","btc"]},"chain":{"type":"string","enum":["base","polygon","solana","auto"]},"status":{"type":"string","enum":["created","settled","expired","cancelled"]},"node_operator":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"El nodeit que lo liquidó."},"payer_address":{"anyOf":[{"type":"string"},{"type":"null"}]},"tx_hash":{"anyOf":[{"type":"string"},{"type":"null"}]},"fee_amount":{"type":"integer","description":"La comisión (nodeit + tesorería), en unidades base. Tras liquidar, la que cobró el contrato."},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"created_at":{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},"expires_at":{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},"settled_at":{"anyOf":[{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},{"type":"null"}]},"client_secret":{"description":"Abre el checkout público de este cobro. Solo lo ve su comercio.","anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","merchant_id","amount","currency","chain","status","node_operator","payer_address","tx_hash","fee_amount","metadata","created_at","expires_at","settled_at"],"additionalProperties":false,"description":"Un cobro. `created` → `settled` cuando la cadena confirma el pago; `cancelled` y `expired` solo sin un pago en camino. No hay `failed`."},"PaymentIntentList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentIntent"}},"has_more":{"type":"boolean"}},"required":["data","has_more"],"additionalProperties":false,"description":"Del más nuevo al más antiguo. Con `has_more`, la siguiente página con `starting_after`."},"RotateWebhookSecret":{"type":"object","properties":{"keep_previous_for":{"default":86400,"description":"Segundos que el secreto anterior sigue firmando junto al nuevo. Por defecto 86400 (24 h); máximo 604800 (7 días). Con `0` deja de valer en el acto: para un secreto que se filtró.","type":"integer","minimum":0,"maximum":604800}},"description":"Cuánto convive el secreto anterior con el nuevo. El cuerpo se puede omitir."},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["payment_intent.created","payment_intent.settled","payment_intent.expired","payment_intent.cancelled"]}},"previous_secret_expires_at":{"anyOf":[{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},{"type":"null"}],"description":"Hasta cuándo se firma también con el secreto anterior, si hay una rotación en curso; `null` si no."}},"required":["id","url","events","previous_secret_expires_at"],"additionalProperties":false,"description":"Un endpoint registrado."},"WebhookEndpointCreated":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["payment_intent.created","payment_intent.settled","payment_intent.expired","payment_intent.cancelled"]}},"secret":{"type":"string","description":"Firma los envíos (cabecera `X-Signature`). **Solo se devuelve aquí**: guárdalo."},"created_at":{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."}},"required":["id","url","events","secret","created_at"],"additionalProperties":false,"description":"El endpoint recién registrado, con el secreto con el que se firman sus envíos."},"WebhookEndpointList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}},"has_more":{"type":"boolean"}},"required":["data","has_more"],"additionalProperties":false,"description":"Los endpoints activos del comercio."},"WebhookEvent":{"type":"object","properties":{"id":{"type":"string","description":"Estable: el mismo evento conserva su id en reintentos y reenvíos."},"type":{"type":"string","enum":["payment_intent.created","payment_intent.settled","payment_intent.expired","payment_intent.cancelled"]},"created":{"type":"integer","minimum":0,"description":"Cuándo ocurrió el cambio de estado, no cuándo se envió."},"data":{"description":"El cobro tal como quedó en ese momento.","$ref":"#/components/schemas/PaymentIntent"}},"required":["id","type","created","data"],"additionalProperties":false,"description":"Lo que recibe el endpoint del comercio. Firmado con HMAC-SHA256: cabecera `X-Signature: t=<timestamp>,v1=<hex>` sobre `<timestamp>.<cuerpo>`; tras rotar el secreto lleva dos `v1` durante la ventana, y vale si coincide cualquiera. Entrega al menos una vez y sin orden: deduplica por `id`."},"WebhookSecretRotated":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["payment_intent.created","payment_intent.settled","payment_intent.expired","payment_intent.cancelled"]}},"secret":{"type":"string","description":"El secreto nuevo: firma los envíos desde ahora. **Solo se devuelve aquí**: guárdalo."},"previous_secret_expires_at":{"anyOf":[{"type":"integer","minimum":0,"description":"Segundos desde 1970 (UTC)."},{"type":"null"}],"description":"Hasta cuándo se firma también con el secreto anterior, si hay una rotación en curso; `null` si no."}},"required":["id","url","events","secret","previous_secret_expires_at"],"additionalProperties":false,"description":"El endpoint con su secreto nuevo. Mientras `previous_secret_expires_at` no pase, cada envío lleva dos firmas (`v1`), la del secreto nuevo y la del anterior: el verificador acepta cualquiera."},"X402Verification":{"type":"object","properties":{"verified":{"type":"boolean","const":true},"tx_hash":{"type":"string"},"amount_received":{"type":"number"}},"required":["verified","tx_hash","amount_received"],"additionalProperties":false,"description":"El pago existe en la cadena, cubre el precio y no se había usado."},"X402VerifyRequest":{"type":"object","properties":{"payment":{"type":"string","minLength":1,"description":"La cabecera `X-PAYMENT` tal como llegó: JSON en base64 con `tx_hash` y `amount`."},"amount":{"type":"integer","exclusiveMinimum":0,"description":"El precio de la petición, en unidades base de USDC."},"chain":{"type":"string","enum":["base"]}},"required":["payment","amount","chain"],"description":"Un pago x402 a verificar contra la cadena."}}}}