Back to top

Global Ledger v1 Webhooks — Client Integration Guide

This guide shows how to receive Global Ledger events (address score updates and alerts) on your own HTTPS endpoint using the v1 Integration API. It assumes you already have an API key, an API secret, and a callback URL. All requests go to your blockchain subdomain, for example https://btc.glprotocol.com/integration.

Purpose and mental model

Webhook delivery uses two building blocks:

  • A webhook endpoint is a callback destination: a URL plus an enabled state, identified by a webhookId you choose.

  • A webhook binding selects which events are delivered to that destination. A binding is an event route: a type, an optional subType, and an optional coin.

One endpoint may have any number of bindings. Create the endpoint once, then attach one binding per event route you want to receive. Bindings are persistent by default; a one-shot binding (isOneShot: true) is removed after its first successful delivery and is meant only for temporary callbacks.

Quick start

  1. Create (or update) a webhook endpoint. PUT requests must be signed — see Authentication and signing.

    curl -X PUT "https://btc.glprotocol.com/integration/webhooks/{WEBHOOK_ID}" \
      -H "Authorization: {API_KEY}" \
      -H "X-Signature: {SIGNATURE}" \
      -H "Content-Type: application/json" \
      -d '{"url": "{CALLBACK_URL}", "enabled": true}'

    A new endpoint returns 201 with the stored object; an update returns 200.

  2. Create a binding for the events you want. For address score updates:

    curl -X POST "https://btc.glprotocol.com/integration/webhooks/{WEBHOOK_ID}/bindings" \
      -H "Authorization: {API_KEY}" \
      -H "X-Signature: {SIGNATURE}" \
      -H "Content-Type: application/json" \
      -d '{"type": "monitoring.score", "coin": "btc"}'

    The response is 201 with the created binding, including its id:

    {
      "id": "{BINDING_ID}",
      "webhookId": "{WEBHOOK_ID}",
      "type": "monitoring.score",
      "coin": "btc",
      "isOneShot": false,
      "createdAt": "2026-07-21T12:00:00.000Z"
    }

    Note the two identifiers: webhookId is the endpoint id you chose in step 1; id is the binding id generated by the API. You need the binding id to delete that binding later.

  3. Perform the prerequisite product action. Score updates are produced only for addresses that are monitored for your account, so make sure the address is in monitoring (see Address score flow). Alerts require an alert configured in your Global Ledger account.

  4. Receive and verify the callback on {CALLBACK_URL} (see Authentication and signing for verification).

  5. List and remove bindings when routes change:

    curl "https://btc.glprotocol.com/integration/webhooks/{WEBHOOK_ID}/bindings" \
      -H "Authorization: {API_KEY}"
    
    curl -X DELETE "https://btc.glprotocol.com/integration/webhooks/{WEBHOOK_ID}/bindings/{BINDING_ID}" \
      -H "Authorization: {API_KEY}"

Event selection

type subType coin Delivered when
monitoring.score none (must be omitted) optional The score of a monitored address is updated
alert monitoring optional A configured alert produces a new alert event
alert risk-report optional A configured risk-report alert produces a new alert event
alert behavior-alert optional A behavior alert produces a new alert event

Only the values above are accepted. monitoring.score takes no subType; sending one is rejected. Omit subType or coin when you do not need them — never send null, "null", or an empty string. On a blockchain-specific subdomain, an explicit coin must match that blockchain.

Address score flow

  1. Keep a persistent monitoring.score binding on your endpoint (quick start step 2).

  2. Make sure the address is monitored for your account through the v1 monitoring lifecycle. Creating a binding does not add any address to monitoring; the binding only routes events. The compatibility endpoint PUT /integration/webhooks/{WEBHOOK_ID}/subscription/score/address (deprecated, see Deprecated legacy flow) adds addresses to monitoring for the webhook’s account.

  3. When a monitored address’s score changes, the update is delivered to every enabled endpoint of yours whose binding matches the event route.

Alert flow

  1. Create a persistent alert binding with one supported subType, for example risk-report alerts:

    curl -X POST "https://btc.glprotocol.com/integration/webhooks/{WEBHOOK_ID}/bindings" \
      -H "Authorization: {API_KEY}" \
      -H "X-Signature: {SIGNATURE}" \
      -H "Content-Type: application/json" \
      -d '{"type": "alert", "subType": "risk-report", "coin": "btc"}'
  2. Alerts are configured in your Global Ledger account; the binding only routes the resulting events. An alert callback is delivered when an alert produces a new alert event — repeated recalculations of an event that was already delivered are not sent again.

Authentication and signing

Authenticate every webhook API request with your API key passed as the Authorization header value, without a Bearer prefix. This is the recommended authorization method for all webhook operations, and every example in this guide uses it.

On top of that, there are two separate signature operations. Both use the same formula, with your API secret as the HMAC key:

signature = base64( HMAC-SHA256( secret = {API_SECRET},
                                 input  = "{API_KEY}" + "." + <compact JSON body> ) )

Signing your API requests. POST and PUT requests require the X-Signature header computed over the exact JSON body you send. GET and DELETE requests need only the Authorization header. In JavaScript:

const crypto = require("crypto");
const body = JSON.stringify({ type: "monitoring.score", coin: "btc" });
const signature = crypto
  .createHmac("sha256", API_SECRET)
  .update(`${API_KEY}.${body}`)
  .digest("base64");
// send `body` as the request body and `signature` as X-Signature

Verifying incoming callbacks. Each callback is an HTTPS POST to your callback URL with these headers:

Authorization: {API_KEY}
X-SIGNATURE: <base64 HMAC of "{API_KEY}." + callback body>
X-GL-WEBHOOK-ID: {WEBHOOK_ID}
X-GL-WEBHOOK-TYPE: monitoring.score
X-GL-WEBHOOK-COIN: btc

X-GL-WEBHOOK-SUBTYPE is present when the event route has a subtype; X-GL-WEBHOOK-COIN is present when the event has a coin. Recompute the HMAC over {API_KEY}. plus the received body (compact JSON, exactly as delivered — in JavaScript, JSON.stringify(JSON.parse(rawBody)) yields the same string) and compare it with X-SIGNATURE.

A monitoring.score callback body is an array of score updates:

[
  {
    "address": "{ADDRESS}",
    "score": 42.7,
    "timestamp": "2026-07-21T12:34:56.000Z",
    "coin": "btc"
  }
]

An alert callback body contains the new alert events:

{
  "subjects": [
    {
      "subjectId": "664f73107e88eb9ebaafb5d4",
      "alertId": "664f73107e88eb9ebaafb5d5",
      "title": "High risk exposure",
      "priority": 2,
      "address": "{ADDRESS}",
      "directTx": ""
    }
  ]
}

Additional fields may be present in either body; use the route headers, not the body shape, to dispatch events.

Lifecycle operations

  • GET /integration/webhooks/{WEBHOOK_ID}/bindings lists bindings for one endpoint; GET /integration/webhook-bindings lists bindings across all your endpoints. Both accept type, subType, coin, and isOneShot query filters.

  • DELETE /integration/webhooks/{WEBHOOK_ID}/bindings/{BINDING_ID} removes one binding by id — the recommended way to remove a route.

  • Advanced: POST .../bindings/delete-by-selector (per endpoint or account-wide under /integration/webhook-bindings/delete-by-selector) deletes bindings matching a route selector in bulk. By default the match is exact: an omitted subType or coin matches only bindings without that field. Crossing those dimensions requires explicit includeSubTypes / includeCoins flags plus confirm: true. Prefer deletion by binding id unless you really need bulk cleanup.

  • Deleting a webhook endpoint (DELETE /integration/webhooks/{WEBHOOK_ID}) also removes its bindings.

Deprecated legacy flow

Two older operations remain for compatibility. They are deprecated and will be removed in a future release:

  • POST /integration/score/address — one-shot score delivery and legacy subscribe: true monitoring setup.

  • PUT /integration/webhooks/{WEBHOOK_ID}/subscription/score/address — adds addresses to (or removes them from) monitoring for a webhook.

New integrations should use a webhook endpoint plus bindings for all event routing. The legacy events field on the webhook endpoint is stored and returned for compatibility but is ignored for routing.

Troubleshooting checklist

  • The endpoint is enabled: true (check GET /integration/webhooks/{WEBHOOK_ID}).

  • A binding exists whose type/subType/coin match the expected event (check the binding list and the X-GL-WEBHOOK-* headers of any callback).

  • Optional fields are omitted, not sent as null, "null", or "".

  • For score events, the address is actually monitored for your account — creating a binding alone does not start monitoring.

  • Signature verification uses the exact delivered body representation (compact JSON) with the input {API_KEY}.<body> and your API secret as the HMAC key.

  • One-shot bindings disappear after their first delivery — recreate them if you expected repeated callbacks.

Generated by aglio on 24 Jul 2026