- APIs
- Chainhooks API
- Usage
Usage
Learn how to authenticate, make requests, and handle responses with the Chainhooks API
Authentication
All Chainhooks API requests require authentication using a Hiro API key.
Get Your API Key
- 1Visit platform.hiro.so
- 2Sign in or create an account
- 3Navigate to API Keys
- 4Generate or copy your API key
Using Your API Key
Include your API key in the x-api-key header for all requests:
curl https://api.testnet.hiro.so/chainhooks/v1/me/ \-H "x-api-key: YOUR_API_KEY"
Security best practices:
- Store API keys in environment variables, never in code
- Use different keys for development and production
- Rotate keys periodically
- Never commit keys to version control
Base URLs
Use the appropriate base URL for your environment:
Testnet: https://api.testnet.hiro.so/chainhooks/v1Mainnet: https://api.mainnet.hiro.so/chainhooks/v1
Always test on testnet first before deploying to mainnet.
Request Format
Headers
All requests should include:
Content-Type: application/jsonx-api-key: YOUR_API_KEY
Request Body
Most endpoints accept JSON request bodies. Example for registering a chainhook:
curl -X POST https://api.testnet.hiro.so/chainhooks/v1/me/ \-H "x-api-key: YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"name": "my-chainhook","version": "1","chain": "stacks","network": "testnet","filters": {"events": [{"type": "stx_transfer","sender": "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM"}]},"action": {"type": "http_post","url": "https://example.com/webhooks"}}'
Response Format
Success Responses
Successful responses return JSON with relevant data:
{"uuid": "123e4567-e89b-12d3-a456-426614174000","definition": {"name": "my-chainhook","version": "1","chain": "stacks","network": "testnet",...},"status": {"status": "new","enabled": false,"created_at": 1234567890,...}}
HTTP Status Codes
| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request succeeded, response body contains data |
| 204 | No Content | Request succeeded, no response body |
| 400 | Bad Request | Invalid request format or parameters |
| 401 | Unauthorized | Missing or invalid API key |
| 404 | Not Found | Chainhook UUID not found |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Server Error | Internal server error |
Error Responses
Error responses include details about what went wrong:
{"error": "Invalid request body","details": "filters.events is required"}
Common Patterns
List All Chainhooks
curl https://api.testnet.hiro.so/chainhooks/v1/me/ \-H "x-api-key: YOUR_API_KEY"
Get a Specific Chainhook
curl https://api.testnet.hiro.so/chainhooks/v1/me/{uuid} \-H "x-api-key: YOUR_API_KEY"
Enable a Chainhook
curl -X PATCH https://api.testnet.hiro.so/chainhooks/v1/me/{uuid}/enabled \-H "x-api-key: YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"enabled": true}'
Delete a Chainhook
curl -X DELETE https://api.testnet.hiro.so/chainhooks/v1/me/{uuid} \-H "x-api-key: YOUR_API_KEY"
Evaluate Against a Block
Test your chainhook against a specific block:
curl -X POST https://api.testnet.hiro.so/chainhooks/v1/me/{uuid}/evaluate \-H "x-api-key: YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"block_height": 150000}'
Bulk Enable/Disable
Enable or disable multiple chainhooks matching filters:
curl -X PATCH https://api.testnet.hiro.so/chainhooks/v1/me/enabled \-H "x-api-key: YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"enabled": false,"filters": {"webhook_url": "https://old-endpoint.com/webhooks"}}'
Rate Limits
The Chainhooks API enforces rate limits based on your subscription tier:
- Free tier: 100 requests per minute
- Pro tier: 1000 requests per minute
- Enterprise: Custom limits
When rate limited, you'll receive a 429 Too Many Requests response. Implement exponential backoff in your application:
async function makeRequestWithRetry(url, options, maxRetries = 3) {for (let i = 0; i < maxRetries; i++) {const response = await fetch(url, options);if (response.status === 429) {const delay = Math.pow(2, i) * 1000;await new Promise(resolve => setTimeout(resolve, delay));continue;}return response;}throw new Error('Max retries exceeded');}
Webhook Security
Consumer Secret
When you register a chainhook, webhook payloads include an x-chainhook-consumer-secret header. Validate this secret in your webhook endpoint:
app.post('/webhooks', (req, res) => {const receivedSecret = req.headers['x-chainhook-consumer-secret'];const expectedSecret = process.env.CHAINHOOK_CONSUMER_SECRET;if (receivedSecret !== expectedSecret) {return res.status(401).send('Unauthorized');}// Process webhook payloadres.sendStatus(200);});
Rotate Secret
Periodically rotate your consumer secret:
curl -X POST https://api.testnet.hiro.so/chainhooks/v1/me/secret \-H "x-api-key: YOUR_API_KEY"
Store the new secret securely and update your webhook endpoint.
Best Practices
- 1Start on testnet - Always test chainhooks on testnet before mainnet
- 2Enable gradually - Create chainhooks disabled, test with
evaluate, then enable - 3Handle errors - Implement proper error handling and retries
- 4Validate webhooks - Always verify the consumer secret header
- 5Use HTTPS - Webhook URLs must use HTTPS for security
- 6Monitor usage - Track API usage to stay within rate limits
- 7Version control - Document your chainhook configurations
- 8Clean up - Delete unused chainhooks to reduce costs
Pagination
List endpoints support pagination via query parameters:
# Get first page (default: 20 results)curl "https://api.testnet.hiro.so/chainhooks/v1/me/?limit=20&offset=0" \-H "x-api-key: YOUR_API_KEY"# Get next pagecurl "https://api.testnet.hiro.so/chainhooks/v1/me/?limit=20&offset=20" \-H "x-api-key: YOUR_API_KEY"
Response includes pagination metadata:
{"limit": 20,"offset": 0,"total": 45,"results": [...]}