Getting Started
FalconHook delivers real-time webhook notifications for Algorand blockchain events. Define rules that filter transactions, point them at your endpoint, and receive signed POST requests within milliseconds of block finalization.
Quick Start
- Register — create your account at /register
- Create an API key —
POST /api/auth/keys - Register a webhook endpoint —
POST /api/endpoints - Create a rule — define filters + link to your endpoint
- Start receiving webhooks!
Base URL
https://falconhook.com/api
All endpoints below are relative to this base. For example, POST /api/rules → https://falconhook.com/api/rules
Authentication
FalconHook supports two authentication methods: JWT tokens (for web sessions) and API keys (for programmatic access).
JWT Login
POST /api/auth/login
Content-Type: application/json
{
"email": "you@example.com",
"password": "your-password"
}
// Response: { "access_token": "eyJ...", "token_type": "bearer" }API Key Authentication
Pass your API key in the X-Api-Key header with every request:
curl -X GET https://falconhook.com/api/rules \ -H "X-Api-Key: key_your-api-key-here"
Rate Limits
API requests are rate-limited per tenant using a sliding window. Every response includes rate-limit headers so you can track usage.
Response Headers
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests per minute for your plan |
| X-RateLimit-Remaining | Requests remaining in the current window |
| X-RateLimit-Reset | Unix timestamp when the window resets |
429 Response
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1719500060
{
"error": "Rate limit exceeded. Limit: 30 requests/minute",
"detail": "Rate limit exceeded. Limit: 30 requests/minute",
"status": 429,
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}Error Responses
All error responses follow a consistent JSON format. Every response includes an X-Request-ID header for tracing.
Error Format
{
"error": "Human-readable error message",
"detail": "Detailed description",
"status": 400,
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}Common Status Codes
| Code | Meaning |
|---|---|
| 400 | Bad request — malformed payload or validation error |
| 401 | Unauthorized — missing or invalid API key / JWT |
| 403 | Forbidden — insufficient permissions |
| 404 | Not found — resource does not exist |
| 409 | Conflict — unique constraint violation |
| 422 | Unprocessable entity — Pydantic validation error |
| 429 | Too many requests — rate limit exceeded |
| 500 | Internal server error |
API Keys
Manage API keys for programmatic access. The secret is shown only once at creation time — save it securely.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/keys | Create a new API key |
| GET | /api/auth/keys | List your API keys (secrets hidden) |
| PATCH | /api/auth/keys/{key_id} | Update name or scopes |
| DELETE | /api/auth/keys/{key_id} | Revoke an API key |
| POST | /api/auth/keys/{key_id}/rotate | Rotate key (with optional grace period) |
| GET | /api/auth/keys/me | Introspect current API key |
Rules
Rules define which blockchain transactions trigger webhook deliveries. Combine multiple filters for precise matching.
Rule Fields
| Field | Type | Description |
|---|---|---|
| name | string | Rule name (3–64 chars, alphanumeric + hyphens) |
| sender | string? | Algorand sender address (58 chars) |
| receiver | string? | Algorand receiver address (58 chars) |
| txn_type | string? | pay | axfer | appl | keyreg | acfg | afrz | stpf |
| asset_id | int? | Filter by ASA ID |
| app_id | int? | Filter by application ID |
| min_amount | int? | Minimum transaction amount (microAlgos) |
| endpoint_id | int? | Link to a registered webhook endpoint |
| max_retries | int | Retry attempts on failure (0–20, default 6) |
| retry_delay_seconds | int | Initial retry delay in seconds (default 1) |
| delivery_mode | string | batch (default) or individual (Pro+) |
| max_batch_size | int? | Max txns per POST, 1–500 (Pro+) |
| project_id | int? | Scope rule to a specific project |
| abi_method | string? | ARC-4 ABI method signature (e.g. transfer(address,uint64)uint64) |
| arc28_event | string? | ARC-28 event signature (e.g. Transfer(address,address,uint64)) |
| include_inner_txns | bool? | Also match inside inner transactions (any txn type) |
| embed_inner_txns | bool? | Embed full inner txn details in appl event payload (appl/any only) |
Create a Rule
POST /api/rules
Content-Type: application/json
X-Api-Key: key_your-key
{
"name": "whale-payments",
"txn_type": "pay",
"min_amount": 1000000000,
"endpoint_id": 1,
"max_retries": 6
}API Routes
| Method | Path | Description |
|---|---|---|
| POST | /api/rules | Create a new rule |
| GET | /api/rules | List all rules |
| GET | /api/rules/{id} | Get a single rule |
| PUT | /api/rules/{id} | Full update |
| PATCH | /api/rules/{id} | Partial update |
| PATCH | /api/rules/{id}/active | Toggle active/inactive |
| DELETE | /api/rules/{id} | Delete a rule |
Webhook Endpoints
Register your webhook URLs as managed endpoints. Each endpoint gets a unique signing secret (shown only once at creation). Link rules to endpoints via endpoint_id.
Create an Endpoint
POST /api/endpoints
Content-Type: application/json
X-Api-Key: key_your-key
{
"name": "Production Server",
"url": "https://yourapp.com/webhook",
"verification_level": "standard"
}
// Response includes "secret" — save it! It won't be shown again.Verification Levels
- standard — Challenge-response HMAC verification (default)
- manual — 6-digit code sent to endpoint, confirmed via API
API Routes
| Method | Path | Description |
|---|---|---|
| POST | /api/endpoints | Create endpoint |
| GET | /api/endpoints | List all endpoints |
| GET | /api/endpoints/{id} | Get one endpoint |
| PUT | /api/endpoints/{id} | Update endpoint |
| DELETE | /api/endpoints/{id} | Delete endpoint |
| POST | /api/endpoints/{id}/verify | Verify endpoint |
| POST | /api/endpoints/{id}/test | Send test event |
| POST | /api/endpoints/{id}/rotate-secret | Rotate signing secret |
Webhook Delivery
When a transaction matches your rule, FalconHook sends a signed POST to your endpoint. The payload format depends on your delivery mode.
Batch Mode (default)
POST https://yourapp.com/webhook
Content-Type: application/json
X-FalconHook-Timestamp: 1719500000
X-FalconHook-Signature: base64-hmac-sha256-signature
{
"round": 42000000,
"network": "mainnet",
"transactions": [
{
"txn_id": "TXID...",
"payload": {
"sender": "ALGO...",
"receiver": "ALGO...",
"amount": 1000000,
"type": "pay"
},
"matched_rules": [
{ "rule": "whale-payments", "project": "Main" }
]
}
],
"idempotency_key": "blk-123-x1"
}Individual Mode (Pro+)
{
"round": 42000000,
"network": "mainnet",
"transaction": {
"txn_id": "TXID...",
"payload": { ... },
"matched_rules": [
{ "rule": "whale-payments" }
]
},
"idempotency_key": "dlv-456"
}Payload Fields
| Field | Type | Description |
|---|---|---|
| round | integer | Block round number |
| network | string | "mainnet" or "testnet" |
| block_timestamp | integer? | Block timestamp (Unix seconds), if available |
| transaction | object | Single transaction (individual mode) |
| transactions | array | Array of transactions (batch mode) |
| transactions[].txn_id | string | Algorand transaction ID |
| transactions[].payload | object | Raw Algorand transaction fields |
| transactions[].matched_rules | array | Rules that matched: [{ rule, project? }] |
| idempotency_key | string | Unique key for deduplication |
HTTP Headers
| Header | Description |
|---|---|
| Content-Type | application/json |
| X-FalconHook-Timestamp | Unix timestamp (seconds) when the request was signed |
| X-FalconHook-Signature | Base64-encoded HMAC-SHA256 signature |
Retry Policy
Failed deliveries retry with exponential backoff, configurable per rule. See Retries & Dead Letters for the full backoff schedule, per-plan limits, and dead-letter queue details.
Signature Verification
Every webhook is signed with HMAC-SHA256. Verify the signature to ensure authenticity and prevent replay attacks.
How Signing Works
- Read the
X-FalconHook-Timestampheader (Unix seconds) - Build the message:
"{timestamp}.{raw_body}" - Compute HMAC-SHA256 using your endpoint's signing secret
- Base64-encode and compare with
X-FalconHook-Signature - Reject if timestamp is older than 300 seconds (replay protection)
Python Example
import hmac, hashlib, base64, time
def verify(body: bytes, timestamp: str, signature: str, secret: str):
# Replay protection: reject old timestamps
if abs(time.time() - int(timestamp)) > 300:
raise ValueError("Timestamp too old — possible replay attack")
message = f"{timestamp}.".encode() + body
expected = base64.b64encode(
hmac.new(secret.encode(), message, hashlib.sha256).digest()
).decode()
if not hmac.compare_digest(expected, signature):
raise ValueError("Invalid signature")Node.js Example
const crypto = require('crypto');
function verify(body, timestamp, signature, secret) {
const age = Math.abs(Date.now() / 1000 - parseInt(timestamp));
if (age > 300) throw new Error('Timestamp too old');
const message = timestamp + '.' + body;
const expected = crypto
.createHmac('sha256', secret)
.update(message)
.digest('base64');
if (expected !== signature) throw new Error('Invalid signature');
}Retries & Dead Letters
Failed webhook deliveries (4xx / 5xx responses) are retried with exponential backoff. After all attempts are exhausted, the delivery moves to the dead-letter queue for manual inspection and replay.
Backoff Schedule
Delay = min(2^attempt, 60) seconds. Example for 6 retries:
| Attempt | Delay |
|---|---|
| 1 | 2 s |
| 2 | 4 s |
| 3 | 8 s |
| 4 | 16 s |
| 5 | 32 s |
| 6 | 60 s (cap) |
Max Retries by Plan
| Plan | Max Retries |
|---|---|
| Free | 3 |
| Hobby | 5 |
| Pro | 6 |
| Business | 10 |
| Enterprise | 10 |
Dead-Letter Queue
- Deliveries that exceed
max_retriesmove to dead status - Dead letters are never retried automatically
- Inspect via
GET /api/deliveries/dead - Requeue all with
POST /api/deliveries/dead/requeue - Or replay individual deliveries with
POST /api/deliveries/{id}/replay
HTTP 429 Handling
When your endpoint returns 429 Too Many Requests, FalconHook respects the Retry-After header (capped at 120 s) before the next attempt.
Events
Events represent blockchain transactions processed by FalconHook. Query, filter, and manage past events via the API.
| Method | Path | Description |
|---|---|---|
| GET | /api/events | List events (filter by txn_type, project_id, matched, date range) |
| GET | /api/events/metrics | Event statistics |
| GET | /api/events/distributions | Event distribution analytics |
| GET | /api/events/timeseries | Events over time |
| POST | /api/events/bulk-delete | Bulk delete events by ID |
Query Parameters
txn_type— filter by transaction typeproject_id— scope to projectmatched— true/falsecreated_at_start/created_at_end— ISO 8601 date rangelimit/offset— pagination
Deliveries
Track, retry, and manage webhook deliveries. Each delivery has a lifecycle: queued → delivering → success | failed → dead.
| Method | Path | Description |
|---|---|---|
| GET | /api/deliveries | List deliveries |
| POST | /api/deliveries/{id}/retry | Retry a delivery |
| POST | /api/deliveries/{id}/replay | Replay a delivery |
| POST | /api/deliveries/bulk-retry | Bulk retry |
| POST | /api/deliveries/retry_all_failed | Retry all failed |
| GET | /api/deliveries/dead | View dead-letter queue |
| POST | /api/deliveries/dead/requeue | Requeue dead letters |
| GET | /api/deliveries/metrics | Delivery statistics |
Replay
Re-evaluate historical events against your current rules. Useful for backfilling or testing new rules against past data.
POST /api/replay/rules/{rule_id}
Content-Type: application/json
X-Api-Key: key_your-key
{
"from_date": "2025-01-01T00:00:00Z",
"to_date": "2025-01-31T23:59:59Z",
"txn_type": "pay",
"network": "mainnet",
"limit": 5000
}
// Response:
// {
// "rule_id": 42,
// "events_scanned": 5000,
// "matches_found": 12,
// "matches": [...]
// }Real-Time Streaming
In addition to webhooks, subscribe to live events via Server-Sent Events (SSE) or WebSockets.
| Protocol | Path | Description |
|---|---|---|
| SSE | /api/events/stream | Server-Sent Events for live matched events |
| WS | /api/events/ws | WebSocket stream for live events |
| SSE | /api/blocks/stream | Live blockchain block stream |
SSE Example
curl -N -H "X-Api-Key: key_your-key" \ https://falconhook.com/api/events/stream
FAQ
What's the delivery guarantee?
At-least-once delivery with configurable retries (up to 20) and exponential backoff. Failed deliveries are stored in a dead-letter queue for manual replay.
How fast are notifications?
Typically 200–500ms from block finalization to your endpoint. We process every block in real-time.
Which networks are supported?
Algorand MainNet is supported today. TestNet and BetaNet can be added based on demand.
Can I test webhooks locally?
Yes — use ngrok or similar tunnels, or hit POST /api/endpoints/{id}/test to send a test event to any registered endpoint.
What transaction types can I filter?
pay (payments), axfer (ASA transfers), appl (app calls), keyreg (key registration), acfg (asset config), afrz (asset freeze), and stpf (state proofs).
Ready to Get Started?
Create your free account and start receiving webhooks in minutes.