Skip to main content

Webhooks

Webhooks allow your agent to receive real-time HTTP notifications when events occur on DobProtocol. Instead of polling endpoints for changes, register a webhook URL and DobProtocol will send a POST request to your server whenever a subscribed event fires.

All webhook management endpoints require an API key with the read scope.

Authentication: X-API-Key header (read scope)

Event Types

EventDescriptionTrigger
distribution_createdA new distribution round was created for a poolAdmin creates distribution
claim_availableA distribution round is now claimable (claim window opened)Claim delay period ends
shares_transferredShares were transferred between walletsDirect transfer or airdrop
pool_createdA new pool was deployed on-chainPool initialization
marketplace_listing_createdNew shares listed for saleSeller creates listing
marketplace_sale_completedA marketplace purchase completedBuyer completes purchase
crowdfunding_finalizedCrowdfunding target reached, pool activatedTarget amount met
crowdfunding_failedCrowdfunding deadline passed without reaching targetDeadline expires

Register Webhook

Register a new webhook endpoint to receive event notifications.

POST /api/agent/webhooks

Request Body:

FieldTypeRequiredDescription
urlstringYesHTTPS URL to receive webhook POST requests
eventsstring[]YesList of event types to subscribe to
secretstringYesShared secret for HMAC signature verification (min 16 characters)

curl:

curl -X POST https://home.dobprotocol.com/api/agent/webhooks \
-H "X-API-Key: dob_ak_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/dob-events",
"events": [
"distribution_created",
"claim_available",
"marketplace_sale_completed"
],
"secret": "whsec_a1b2c3d4e5f6g7h8i9j0"
}'

Python:

import requests

resp = requests.post(
"https://home.dobprotocol.com/api/agent/webhooks",
headers={"X-API-Key": API_KEY},
json={
"url": "https://your-server.com/dob-events",
"events": [
"distribution_created",
"claim_available",
"marketplace_sale_completed"
],
"secret": "whsec_a1b2c3d4e5f6g7h8i9j0"
}
)
webhook = resp.json()["data"]
print(f"Webhook ID: {webhook['id']}")

Response (201 Created):

{
"success": true,
"data": {
"id": "wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W",
"url": "https://your-server.com/dob-events",
"events": [
"distribution_created",
"claim_available",
"marketplace_sale_completed"
],
"is_active": true,
"created_at": "2026-03-10T12:00:00Z"
}
}
note

The url must use HTTPS. HTTP URLs are rejected. The secret is never returned in API responses after creation.

Limits: Each API key can register up to 5 webhooks.

List Webhooks

Retrieve all registered webhooks for the API key.

GET /api/agent/webhooks

curl:

curl https://home.dobprotocol.com/api/agent/webhooks \
-H "X-API-Key: dob_ak_your_key_here"

Response (200 OK):

{
"success": true,
"data": [
{
"id": "wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W",
"url": "https://your-server.com/dob-events",
"events": [
"distribution_created",
"claim_available",
"marketplace_sale_completed"
],
"is_active": true,
"failure_count": 0,
"last_triggered_at": "2026-03-10T14:30:00Z",
"created_at": "2026-03-10T12:00:00Z"
}
]
}

Update Webhook

Update the URL, events, or secret for an existing webhook.

PUT /api/agent/webhooks/:id

Path Parameters:

ParameterTypeDescription
idstringWebhook ID

Request Body (all fields optional):

FieldTypeDescription
urlstringNew HTTPS URL
eventsstring[]New event list (replaces existing)
secretstringNew shared secret (min 16 characters)
is_activebooleanEnable or disable the webhook

curl:

curl -X PUT https://home.dobprotocol.com/api/agent/webhooks/wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W \
-H "X-API-Key: dob_ak_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"events": [
"distribution_created",
"claim_available",
"marketplace_sale_completed",
"pool_created"
]
}'

Response (200 OK):

{
"success": true,
"data": {
"id": "wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W",
"url": "https://your-server.com/dob-events",
"events": [
"distribution_created",
"claim_available",
"marketplace_sale_completed",
"pool_created"
],
"is_active": true,
"updated_at": "2026-03-10T15:00:00Z"
}
}

Delete Webhook

Permanently delete a webhook. No further events will be delivered.

DELETE /api/agent/webhooks/:id

curl:

curl -X DELETE https://home.dobprotocol.com/api/agent/webhooks/wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W \
-H "X-API-Key: dob_ak_your_key_here"

Response (200 OK):

{
"success": true,
"data": {
"id": "wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W",
"deleted": true
}
}

Test Webhook

Send a test event to your webhook URL to verify the integration is working.

POST /api/agent/webhooks/:id/test

curl:

curl -X POST https://home.dobprotocol.com/api/agent/webhooks/wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W/test \
-H "X-API-Key: dob_ak_your_key_here"

Response (200 OK):

{
"success": true,
"data": {
"webhook_id": "wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W",
"test_event_sent": true,
"delivery_status": "delivered",
"response_code": 200,
"response_time_ms": 145
}
}

The test event sent to your URL looks like:

{
"event": "test",
"timestamp": "2026-03-10T15:00:00Z",
"webhook_id": "wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W",
"data": {
"message": "This is a test event from DobProtocol Agent API."
}
}

Webhook Delivery

Request Format

When an event fires, DobProtocol sends a POST request to your webhook URL with the following structure:

Headers:

Content-Type: application/json
X-Dob-Signature: sha256=5d41402abc4b2a76b9719d911017c592...
X-Dob-Event: distribution_created
X-Dob-Delivery: dlv_01HQ3K5M7N8P9Q0R1S2T3U4V5W
X-Dob-Timestamp: 1710000000

Body:

{
"event": "distribution_created",
"timestamp": "2026-03-10T15:00:00Z",
"delivery_id": "dlv_01HQ3K5M7N8P9Q0R1S2T3U4V5W",
"data": {
"pool_address": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"pool_name": "Solar Farm Alpha",
"network_id": 10,
"round_id": 6,
"token": "USDC",
"total_amount": "3000.00",
"total_shares": 10000,
"claimable_from": "2026-03-10T16:00:00Z"
}
}

Signature Verification

Every webhook delivery includes an X-Dob-Signature header containing an HMAC-SHA256 signature of the request body, computed with the shared secret you provided when creating the webhook.

Always verify the signature before processing webhook events to ensure the request is authentic.

Python verification:

import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_a1b2c3d4e5f6g7h8i9j0"

def verify_signature(payload: bytes, signature_header: str) -> bool:
"""Verify the X-Dob-Signature header against the payload."""
if not signature_header.startswith("sha256="):
return False
expected_sig = signature_header[7:] # Remove "sha256=" prefix
computed_sig = hmac.new(
WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(computed_sig, expected_sig)

@app.route("/dob-events", methods=["POST"])
def handle_webhook():
payload = request.get_data()
signature = request.headers.get("X-Dob-Signature", "")

if not verify_signature(payload, signature):
abort(401, "Invalid signature")

event = request.json
event_type = event["event"]
data = event["data"]

if event_type == "distribution_created":
print(f"New distribution in {data['pool_name']}: "
f"{data['total_amount']} {data['token']}")
elif event_type == "claim_available":
print(f"Claims now open for round {data['round_id']} "
f"in {data['pool_name']}")
elif event_type == "marketplace_sale_completed":
print(f"Sale completed: {data['shares']} shares "
f"of {data['pool_name']} at {data['price_per_share']}")

return "", 200

if __name__ == "__main__":
app.run(port=8080)

Node.js verification:

curl example shown using Node.js crypto:
# Equivalent in Python with raw HMAC
import hmac, hashlib, json

body = '{"event":"distribution_created","timestamp":"2026-03-10T15:00:00Z",...}'
secret = "whsec_a1b2c3d4e5f6g7h8i9j0"

signature = "sha256=" + hmac.new(
secret.encode(), body.encode(), hashlib.sha256
).hexdigest()
# Compare this with the X-Dob-Signature header

Your Server Must Respond

Your webhook endpoint must return an HTTP 2xx status code within 10 seconds to acknowledge receipt. The response body is ignored.

If your server does not respond with a 2xx status, DobProtocol considers the delivery failed and will retry.

Retry Policy

Failed deliveries are retried with exponential backoff:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry12 hours

After 5 consecutive failures, the webhook is automatically deactivated (is_active set to false). You will need to fix the issue and re-enable the webhook via the Update Webhook endpoint:

curl -X PUT https://home.dobprotocol.com/api/agent/webhooks/wh_01HQ3K5M7N8P9Q0R1S2T3U4V5W \
-H "X-API-Key: dob_ak_your_key_here" \
-H "Content-Type: application/json" \
-d '{"is_active": true}'

The failure_count resets to 0 when the webhook is re-enabled.


Event Payload Reference

distribution_created

{
"event": "distribution_created",
"timestamp": "2026-03-10T15:00:00Z",
"data": {
"pool_address": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"pool_name": "Solar Farm Alpha",
"network_id": 10,
"round_id": 6,
"token": "USDC",
"total_amount": "3000.00",
"total_shares": 10000,
"claimable_from": "2026-03-10T16:00:00Z",
"expires_at": "2027-03-10T15:00:00Z"
}
}

claim_available

{
"event": "claim_available",
"timestamp": "2026-03-10T16:00:00Z",
"data": {
"pool_address": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"pool_name": "Solar Farm Alpha",
"network_id": 10,
"round_id": 6,
"token": "USDC",
"total_amount": "3000.00",
"amount_per_share": "0.30",
"expires_at": "2027-03-10T15:00:00Z"
}
}

shares_transferred

{
"event": "shares_transferred",
"timestamp": "2026-03-10T14:00:00Z",
"data": {
"pool_address": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"pool_name": "Solar Farm Alpha",
"network_id": 10,
"from_address": "GBDM6KRXXJHKVYFJPTPW3WBDKUYVCH7NNEI67DDCP7YX4UHX2GODPHGI",
"to_address": "GDJTUK3ER3M7LFHHWQMFANJA3SEC7QP3LNU3NKGFBLWF4QMFR5HR7I4T",
"shares": 500,
"transaction_hash": "a1b2c3d4..."
}
}

pool_created

{
"event": "pool_created",
"timestamp": "2026-03-10T10:00:00Z",
"data": {
"pool_address": "CB7YQNF8TOVZ5V5MXRHXWKQVHU4ZHR5A6OHCOQZSC8M3XZGKK78TYYZ",
"pool_name": "New Energy Pool",
"pool_ticker": "NEP",
"network_id": 10,
"creator_address": "GBDM6KRXXJHKVYFJPTPW3WBDKUYVCH7NNEI67DDCP7YX4UHX2GODPHGI",
"access_type": "p",
"distribution_type": "tr"
}
}

marketplace_listing_created

{
"event": "marketplace_listing_created",
"timestamp": "2026-03-10T11:00:00Z",
"data": {
"sale_address": "SALE_7f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c",
"pool_address": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"pool_name": "Solar Farm Alpha",
"network_id": 10,
"seller_address": "GDJTUK3ER3M7LFHHWQMFANJA3SEC7QP3LNU3NKGFBLWF4QMFR5HR7I4T",
"shares_amount": 200,
"price_per_share": "1.50",
"payment_token": "USDC"
}
}

marketplace_sale_completed

{
"event": "marketplace_sale_completed",
"timestamp": "2026-03-10T13:00:00Z",
"data": {
"sale_address": "SALE_7f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c",
"pool_address": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
"pool_name": "Solar Farm Alpha",
"network_id": 10,
"seller_address": "GDJTUK3ER3M7LFHHWQMFANJA3SEC7QP3LNU3NKGFBLWF4QMFR5HR7I4T",
"buyer_address": "GDU3QXHDURHXNKFI4H5QC7JTQOCGS63C25FVTTBGROQOLKV7Q2BAWGYP",
"shares": 200,
"price_per_share": "1.50",
"total_price": "300.00",
"payment_token": "USDC",
"transaction_hash": "d4e5f6a7..."
}
}

crowdfunding_finalized

{
"event": "crowdfunding_finalized",
"timestamp": "2026-04-10T00:00:00Z",
"data": {
"pool_address": "CA7QYNF7SOVZ4V4LXQHXWJQVGU3ZGR4A5OHCOQZSC7M2XZFKK67TYXZ",
"pool_name": "Wind Turbine Collective",
"network_id": 10,
"total_raised": "50000.00",
"target_amount": "50000.00",
"contributor_count": 35,
"payment_token": "USDC"
}
}

crowdfunding_failed

{
"event": "crowdfunding_failed",
"timestamp": "2026-04-15T00:00:01Z",
"data": {
"pool_address": "CA7QYNF7SOVZ4V4LXQHXWJQVGU3ZGR4A5OHCOQZSC7M2XZFKK67TYXZ",
"pool_name": "Wind Turbine Collective",
"network_id": 10,
"total_raised": "32500.00",
"target_amount": "50000.00",
"contributor_count": 18,
"refund_status": "processing"
}
}