Mono Colombia

Webhooks

Cross-product webhook conventions for the Mono API.

A webhook is an automatic notification Mono sends to your system the moment something happens — a transfer is approved, a card is charged, a collection is credited. Instead of asking Mono repeatedly whether something changed, your server receives a single HTTPS request as soon as the event occurs.

These conventions apply to every Mono product: Banking, Core, and Bre-B Participant. Each product has its own event catalog; this page documents the shared mechanics that govern all of them.

Before you start

You will need:

  • A publicly accessible HTTPS endpoint (no localhost, no 127.0.0.1).
  • The ability to verify an HMAC-SHA256 signature on every incoming request.
  • An idempotent event handler — Mono retries on failures, so the same event may arrive more than once.

Envelope

Every webhook request body follows the same JSON envelope:

{
  "event": {
    "data": { ... },
    "type": "event_type_or_name"
  },
  "timestamp": "2022-12-29T15:42:08.325158Z"
}
  • event.type — the stable name of the event (e.g. bank_transfer_approved).
  • event.data — the event payload; its schema depends on the event type.
  • timestamp — ISO 8601 UTC timestamp of when the event was generated.

Signature

Each request is signed with a webhook secret you obtain from the Dashboard. The signature and the timestamp travel together in a custom header called Mono-Signature:

Mono-Signature: t=1672328528,v1=662255ca79c4b21914894d32da10189a1482cd0fee56b2765a8b472662ce55ac
  • t — Unix timestamp. Use it to guard against replay attacks by rejecting requests whose timestamp falls outside your tolerance window.
  • v1 — the HMAC-SHA256 signature. Mono currently uses only version v1.

Verifying signatures

Step 1: Extract timestamp and signature

Split Mono-Signature on , to get:

t=1672328528
v1=662255ca79c4b21914894d32da10189a1482cd0fee56b2765a8b472662ce55ac

Step 2: Build the signed payload string

Concatenate the timestamp, a literal ., and the raw request body:

<timestamp>.<payload_rawbody>

Step 3: Compute the expected signature

Use HMAC-SHA256 with your webhook secret as the key and the signed payload string as the message:

require 'openssl'

timestamp = 1672774221
raw_payload = '{"respose_body": "example"}'

signed_payload = "#{timestamp}.#{raw_payload}"
secret = "whsec_example"

hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret, signed_payload)
# => 652fdc1742906b4b23ce2a5f4ac417b52c264fea0207920a5e76330a87239924

Step 4: Compare and validate

Compare the computed HMAC against the v1 value using a constant-time comparison to prevent timing attacks. Then check that the difference between the current time and t is within your acceptable window (typically 5 minutes).

Retry policy

Mono retries failed requests (any non-2xx response) up to ten times with exponential backoff. After the tenth attempt, the event is not retried again.

AttemptDelay from previous
1immediately
230 seconds
31.5 minutes
43.5 minutes
57.5 minutes
615.5 minutes
731.5 minutes
81.06 hours
92.13 hours
104.26 hours

All ten attempts complete within approximately 8.4 hours.

Money fields

Monetary amounts are always represented in the smallest currency unit (cents for COP and USD):

  • 240000 = 2,400.00
  • 160 = 1.60

The exception is fx_rates, which carries the decimal exchange rate directly: "4002.24" = 4002.24.

URL restrictions

Your webhook endpoint must:

  • Start with http or https.
  • Not use localhost or 127.0.0.1 as the host.
  • Be a valid, reachable HTTP/HTTPS URL.

Next steps

On this page