Skip to main content
When developing webhook integrations, you need a way to receive webhook events on your local machine. Since DocIntell can’t reach localhost, you’ll need a tunneling service to expose your local server to the internet. ngrok is the most popular tool for this purpose. It creates a secure tunnel from a public URL to your local machine.

Prerequisites

  • A local webhook endpoint running (e.g., on port 3000)
  • A DocIntell API key

Step 1: Install ngrok

brew install ngrok

Step 2: Create a Free ngrok Account

  1. Sign up at ngrok.com
  2. Get your auth token from the dashboard
  3. Configure ngrok with your token:
ngrok config add-authtoken YOUR_AUTH_TOKEN
A free ngrok account gives you a random URL that changes each time you restart ngrok. For a stable URL, consider ngrok’s paid plans or use the ngrok free static domain feature.

Step 3: Start Your Local Server

First, make sure your webhook endpoint is running locally. Here’s a minimal example:
from flask import Flask, request
import hmac
import hashlib

app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_secret_here"

@app.route("/webhooks/docintel", methods=["POST"])
def handle_webhook():
    # Verify signature
    signature = request.headers.get("X-DocIntell-Signature")
    payload = request.get_data()

    expected = "sha256=" + hmac.new(
        WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        print("⚠️  Invalid signature!")
        return {"error": "Invalid signature"}, 401

    event = request.get_json()
    print(f"✅ Received event: {event['event']}")
    print(f"   Document ID: {event['data']['document_id']}")

    return {"status": "ok"}, 200

if __name__ == "__main__":
    app.run(port=3000, debug=True)

Step 4: Start ngrok

In a new terminal, start ngrok pointing to your local server:
ngrok http 3000
You’ll see output like this:
Session Status                online
Account                       your-email@example.com
Version                       3.x.x
Region                        United States (us)
Forwarding                    https://abc123.ngrok-free.app -> http://localhost:3000
Copy the https:// URL (e.g., https://abc123.ngrok-free.app) - this is your public webhook URL.
Keep the ngrok terminal open while testing. If you close it, the tunnel will shut down and you’ll need to update your webhook URL.

Step 5: Register Your ngrok URL with DocIntell

Create a webhook configuration using your ngrok URL:
curl -X POST https://api.docintell.com/v1/webhooks \
  -H "Authorization: Bearer dk_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://abc123.ngrok-free.app/webhooks/docintel",
    "events": ["document.uploaded", "document.processing.completed", "document.processing.failed"]
  }'
Save the signing_secret from the response! Update your local server’s WEBHOOK_SECRET variable with this value to verify incoming webhooks.

Step 6: Test the Integration

Upload a test document to trigger webhook events:
curl -X POST https://api.docintell.com/v1/documents \
  -H "Authorization: Bearer dk_test_YOUR_API_KEY" \
  -F "file=@test.pdf"
Watch your local terminal - you should see the webhook events arrive:
✅ Received event: document.uploaded
   Document ID: 660e8400-e29b-41d4-a716-446655440001
✅ Received event: document.processing.completed
   Document ID: 660e8400-e29b-41d4-a716-446655440001

Using ngrok’s Web Interface

ngrok provides a local web interface for inspecting webhook traffic. Open http://localhost:4040 in your browser to:
  • View all incoming requests
  • Inspect request headers and body
  • Replay requests for debugging
  • See response details
This is invaluable for debugging signature verification issues or understanding payload structure.

Tips for Development

Use a Static Domain

If you have an ngrok account, you can claim a free static domain to avoid updating your webhook URL each time:
ngrok http 3000 --domain=your-chosen-name.ngrok-free.app

Multiple Environments

For team development, each developer should:
  1. Run their own ngrok tunnel
  2. Create their own webhook configuration in DocIntell
  3. Use test mode API keys (dk_test_...)

Clean Up Test Webhooks

Remember to delete test webhook configurations when done:
curl -X DELETE https://api.docintell.com/v1/webhooks/{webhook_id} \
  -H "Authorization: Bearer dk_test_YOUR_API_KEY"

Alternatives to ngrok

While ngrok is the most popular option, other tunneling services include:
ServiceFree TierNotes
ngrokYes (random URLs)Most popular, great debugging UI
Cloudflare TunnelYesRequires Cloudflare account
localtunnelYesOpen source, simpler setup
Tailscale FunnelYesGood if you already use Tailscale

Troubleshooting

  • Ensure ngrok is still running (check the terminal)
  • Verify your local server is running on the correct port
  • Check that you’re using the HTTPS URL, not HTTP
  • Some corporate firewalls block ngrok - try a different network
  • Make sure you updated WEBHOOK_SECRET with the signing_secret from the webhook creation response
  • Verify you’re using the raw request body, not parsed JSON
  • Check the ngrok web interface (localhost:4040) to see the exact payload being sent
  • Confirm the webhook is registered: GET /v1/webhooks
  • Check that is_active is true
  • Verify you subscribed to the correct events
  • Look at the ngrok web interface for incoming requests
Free ngrok sessions expire after a few hours. Simply restart ngrok and update your webhook URL:
curl -X PATCH https://api.docintell.com/v1/webhooks/{webhook_id} \
  -H "Authorization: Bearer dk_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://NEW_URL.ngrok-free.app/webhooks/docintel"}'

Next Steps

Once your webhooks are working locally: