The Mercado Pago webhook endpoint is a single, shared URL that receives payment status notifications for all tenants (empresas) registered on the platform. When Mercado Pago delivers a notification, the API immediately acknowledges receipt with HTTP 200, identifies the relevant tenant and transaction, verifies the HMAC-SHA256 signature using that tenant’s stored secret, and then enqueues a background task to fetch the authoritative payment status and update the transaction record.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/sistemashm24/pagos_hotspot_api/llms.txt
Use this file to discover all available pages before exploring further.
Main Endpoint
HMAC-SHA256 signature provided by Mercado Pago. Format:
ts=<timestamp>,v1=<hex-digest>. Required for signature verification when the empresa has a webhook_secret configured.Unique request identifier provided by Mercado Pago. Used as part of the HMAC manifest alongside the timestamp and
data.id. Required for signature verification.POST /api/v1/webhook/mercado-pago
Authentication: None — this is a public endpoint. Security is enforced through HMAC-SHA256 signature verification per tenant.
The endpoint always returns HTTP 200 immediately upon receiving a request — even before signature verification or transaction processing completes. This is required by Mercado Pago to prevent automatic retries. All processing happens asynchronously in a background task.
Webhook Payload Structure
Mercado Pago sends a JSON body with the following fields:| Field | Type | Description |
|---|---|---|
type | string | Event type. Handled values: "payment", "test". Other types are logged and acknowledged. |
id | string | Notification ID assigned by Mercado Pago. Used for idempotency tracking. |
action | string | Action that triggered the event, e.g. "payment.updated". |
data.id | string | Payment ID from Mercado Pago. Used as the primary identifier for fetching real payment status and for HMAC manifest construction. |
external_reference | string | (Optional) Reference set during payment creation, used to look up the transaction in the database. Takes priority over data.id for transaction lookup. |
Signature Verification
Mercado Pago signs every webhook delivery using HMAC-SHA256. The API verifies this signature using thewebhook_secret stored (encrypted) for each empresa.
Algorithm: HMAC-SHA256
Key: The empresa’s webhook_secret, decrypted at runtime via SecureTokenManager.
Manifest format:
data_id— the value ofdata.idfrom the webhook payloadx_request_id— the value of theX-Request-Idrequest headertimestamp— thetscomponent extracted from theX-Signatureheader
X-Signature header format:
ts and v1 components are parsed individually. The manifest is constructed, the HMAC digest is computed, and the result is compared with v1 using hmac.compare_digest to prevent timing attacks.
Verification outcomes:
| Condition | Outcome |
|---|---|
webhook_secret configured, valid signature | Verified — processing continues |
webhook_secret configured, invalid signature | Logged as warning — processing continues (not rejected) |
webhook_secret configured, X-Signature header missing | Logged as warning — processing continues |
webhook_secret configured, X-Request-Id header missing | Logged as warning — processing continues |
No webhook_secret configured | No verification — processing continues (not recommended) |
Processing Flow
Acknowledge immediately
The API prepares a
200 OK response base object with status: "received" before any async work begins. This prevents Mercado Pago from retrying the delivery.Parse the payload
The raw request body is decoded and parsed as JSON. If JSON parsing fails, the pre-built
200 response is returned immediately without further processing.Extract key identifiers
The following fields are extracted from the parsed payload:
type, id (notification ID), action, data.id (payment ID / used for HMAC), and external_reference.Look up the transaction
The API searches the
transacciones table. external_reference is tried first; if no match is found, data.id is used as a fallback transaccion_id lookup. If neither resolves to a record, the 200 base response is returned.Identify the empresa
The empresa record is loaded using
empresa_id from the found transaction. If the empresa does not exist, processing is aborted (still returns 200).Verify HMAC signature
If the empresa has
mercado_pago_webhook_secret set, the secret is decrypted and verify_webhook_signature() is called with the X-Signature header, X-Request-Id header, and data.id. The outcome is logged and stored in the response but does not block processing.Enqueue background task (type='payment')
For
type="payment" events, process_mercado_pago_notification() is added to BackgroundTasks. The full webhook dict, notification ID, and database session are passed to the task. The API then returns 200 immediately.Background: idempotency check
The background task checks
transaction.metadata_json["processed_notifications"] for the current notification_id. If already present, the notification is silently ignored. The list is capped at the last 20 processed IDs.Background: fetch real payment status
The empresa’s
mercado_pago_access_token is decrypted and used to call mercado_pago_service.get_payment_status(access_token, payment_id). This is the authoritative status from Mercado Pago — not just the status in the webhook body.Background: update transaction record
transaction.estado_pago is set to the real status returned by the API call (e.g. "approved", "pending", "rejected"). If the status is "approved" and pagada_en is null, it is set to the current UTC timestamp. The notification_id, webhook_processed, and webhook_received_at fields are also updated. A last_webhook summary and the notification_id are recorded in metadata_json. The database transaction is committed.Transaction State Updates
The followingTransaccion model fields are written during webhook processing:
| Field | Type | Description |
|---|---|---|
estado_pago | VARCHAR(20) | Updated to the real status from Mercado Pago API: "approved", "pending", "rejected", or any other status string returned. |
pagada_en | TIMESTAMP | Set to the current UTC time when estado_pago transitions to "approved" and the field is currently NULL. Not overwritten on subsequent approved events. |
notification_id | VARCHAR(100) | Stores the Mercado Pago notification id from the webhook payload. |
webhook_processed | BOOLEAN | Set to true after the background task runs successfully. |
webhook_received_at | TIMESTAMP | Set to the UTC timestamp when the background processing task ran. |
metadata_json | JSONB | Updated with a last_webhook summary and the current notification ID appended to processed_notifications. |
metadata_json structure after processing:
processed_notifications retains the last 20 notification IDs to bound storage growth while still preventing duplicate processing across retries.
Response Body
All responses fromPOST /api/v1/webhook/mercado-pago return HTTP 200. The body varies by outcome:
Successful payment event:
test event:
Additional Endpoints
GET /api/v1/webhook/test-webhook
Health check — verifies the webhook service is reachable. No authentication required.
Response:
GET /api/v1/webhook/transaccion/{external_reference}
Look up a transaction by its external_reference. No authentication required.
Path parameter: external_reference — the reference string associated with the transaction.
Returns 404 if no matching transaction is found.
Response:
POST /api/v1/webhook/empresa/{empresa_id}/configurar-webhook
Store a webhook_secret for a specific empresa. No authentication required on the endpoint itself.
Path parameter: empresa_id — the empresa identifier.
Request body:
400 if webhook_secret is absent from the request body, and 404 if the empresa does not exist.
Response:
GET /api/v1/webhook/empresa/{empresa_id}/estado-webhook
Check the webhook configuration status and transaction statistics for an empresa.
Path parameter: empresa_id — the empresa identifier.
Returns 404 if the empresa does not exist.
Response:
estado field is "configurado" when webhook_secret_configurado is true, and "pendiente" otherwise.
Mercado Pago Dashboard Configuration
To start receiving notifications, register the webhook URL in your Mercado Pago developer dashboard:- Log in to the Mercado Pago developer panel.
- Navigate to Your integrations → Webhooks.
-
Set the notification URL:
-
Subscribe to the
paymentevent type. -
Copy the secret key generated by Mercado Pago and store it on the API using
POST /api/v1/webhook/empresa/{empresa_id}/configurar-webhook.