Skip to main content

Documentation Index

Fetch the complete documentation index at: https://vantagesolutions.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you end-to-end through a working integration: provisioning a key, building a minimal webhook handler with signature verification, subscribing to events, and triggering a test delivery.

Prerequisites

  • A VantageClaw partner organization with a Partner API key issued to you. Keys are admin-provisioned in v1 — contact your VantageClaw representative if you don’t have one yet.
  • A publicly reachable HTTPS URL for your handler. For local development, ngrok or Cloudflare Tunnel work well.
  • Python 3.10+ or Node.js 18+ for the example handler.

Step 1 — Verify your key

Confirm your key is valid and check what scopes it carries:
curl https://app.vantageclaw.ai/api/v1/partner/me \
  -H "Authorization: Bearer vck_test_REPLACE_ME.your_secret_half_here"
You should see your org slug, key ID, and scope list. If you get 401, double-check the full token includes both halves separated by a dot.

Step 2 — Build a minimal webhook handler

This handler reads the raw body, verifies the signature, and returns 200. Save as handler.py:
import hashlib
import hmac
import os
import time
from http.server import BaseHTTPRequestHandler, HTTPServer

SECRET = os.environ["WEBHOOK_SECRET"]
REPLAY_WINDOW_MS = 5 * 60 * 1000


def verify(body: bytes, sig: str, ts: str) -> bool:
    if not sig.startswith("sha256="):
        return False
    try:
        ts_ms = int(ts)
    except ValueError:
        return False
    if abs(int(time.time() * 1000) - ts_ms) > REPLAY_WINDOW_MS:
        return False
    expected = hmac.new(
        SECRET.encode(),
        msg=f"{ts_ms}.".encode() + body,
        digestmod=hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(sig[len("sha256="):], expected)


class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(length)
        sig = self.headers.get("X-VC-Signature", "")
        ts = self.headers.get("X-VC-Timestamp", "")

        if not verify(body, sig, ts):
            self.send_response(401)
            self.end_headers()
            return

        print(f"Verified event: {body.decode()}")
        self.send_response(200)
        self.end_headers()


if __name__ == "__main__":
    HTTPServer(("0.0.0.0", 8080), Handler).serve_forever()
Don’t start it yet — we need the subscription’s secret first.

Step 3 — Subscribe to the test event

Expose your handler to the public internet. With ngrok:
ngrok http 8080
# Note the https://... forwarding URL
Then create the subscription. The response will include a secret field — copy it now, it is shown only once:
curl https://app.vantageclaw.ai/api/v1/partner/webhooks \
  -H "Authorization: Bearer vck_test_REPLACE_ME.your_secret_half_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-ngrok-id.ngrok.io",
    "events": ["vc.test.ping"]
  }'
Response:
{
  "id": "wh_a1b2c3d4-...",
  "secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "url": "https://your-ngrok-id.ngrok.io",
  ...
}
Save the id (wh_...) and the secret (whsec_...) — you’ll need both.
The secret is unrecoverable. If you lose it before saving, delete this subscription and create a new one.

Step 4 — Start your handler with the secret

export WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
python handler.py
You should see Serving HTTP on 0.0.0.0 port 8080.

Step 5 — Trigger the test event

The test endpoint requires you to echo back your stored secret in the request body. This is deliberate: VantageClaw does not cache your secret server-side after creation, so the only way to authorize a test is for you to prove you still hold it.
curl https://app.vantageclaw.ai/api/v1/partner/webhooks/wh_a1b2c3d4-.../test \
  -H "Authorization: Bearer vck_test_REPLACE_ME.your_secret_half_here" \
  -H "Content-Type: application/json" \
  -d '{
    "secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }'
Response (200):
{
  "event_id": "evt_aabbccdd-...",
  "enqueued": true
}
The event is now in the dispatch queue. Within a few seconds your handler should log:
Verified event: {"event":"vc.test.ping","id":"evt_aabbccdd-...","subscription_id":"wh_a1b2c3d4-...","occurred_at":"...","data":{"message":"integration test"}}
The evt_ ID in your handler’s log matches the event_id in the test endpoint’s response — use this for trace correlation. Fire the same test twice and watch your handler. Both deliveries will have different id values (each test invocation generates a fresh envelope ID), so a naive “dedupe on id” handler will process both. In production, dedupe is most useful when the dispatcher retries after a network blip — the same envelope ID arrives twice. To test that scenario, deliberately reject the first delivery (return 500 from your handler for one request) and watch the retry arrive 60 seconds later with the same id. Your handler should recognize the duplicate and short-circuit.

What’s next

Integration test

The full production-readiness checklist.

Webhook security

Verification deep-dive, including Node.js reference code.