Create Webhook API
Register your HTTPS endpoint to receive signed monitor events. The signing secret is returned exactly once in this response; store it immediately, it cannot be retrieved again. Cost: Free per call.
POST webhook registers an HTTPS URL to receive signed monitor events from twitterapis.com. It validates the URL (rejecting private, loopback, link-local, and metadata addresses), creates the webhook record, and returns its id, url, status, created_at, and an HMAC signing secret. The secret is shown only in this response and cannot be retrieved again, so it must be stored immediately. The call costs 0.
Authorization
bearerAuth Pass your API key as a bearer token on every request: Authorization: Bearer <API_KEY>.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/webhook" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/webhooks/twitterapis" }'{ "id": "e4a1f9c2-3b7d-4a88-9f1e-2c6d8b4a5e10", "url": "https://example.com/webhooks/twitterapis", "status": "active", "secret": "whsec_9f1e2c6d8b4a5e10b6f2c1a49e3d4c11", "created_at": "2026-08-13T10:00:00.000Z"}{ "error": "bad_request", "message": "Missing or malformed parameter. Fix the request before retrying."}{ "error": "unauthorized", "message": "The API key is missing, malformed, or revoked. Check the Authorization header."}{ "error": "insufficient_credits", "message": "Your balance is exhausted. Top up your credits to continue."}{ "error": "forbidden", "message": "The acting account is not authorized for this write action, or has no logged-in session."}{ "error": "not_found", "message": "The resource does not exist, for example a deleted tweet or a private account."}{ "error": "rate_limited", "message": "Too many requests. Back off and retry with exponential backoff."}{ "error": "server_error", "message": "Something failed on our side. Retry with backoff; if it persists, contact support."}Pricing
| Unit | Price |
|---|---|
| Per call | Free |
When to use
Use this endpoint to register a delivery URL the first time you want a monitor's events pushed to your own server instead of being polled. Reach for it once, at setup time; to change an existing webhook's URL or pause delivery use the corresponding update endpoint, not another call to this one.
Notes
- signed_payload = "{timestamp}.{raw_body}"; signature = hex(HMAC_SHA256(key = secret, msg = signed_payload)). The header ships as X-TwitterAPIs-Signature: t=<timestamp>,v1=<hex>. Verify with a constant-time comparison, never a plain ===, or the comparison itself leaks the secret to a patient timing attacker.
- At-least-once delivery, 8 attempts over 21 minutes with jitter, dead-lettered after that. A 410 Gone response disables the webhook immediately. Ordering is not guaranteed; sort by tweet id if you need chronological order.
- Use POST /webhook/{id}/test after creating a webhook to fire one real signed test event and confirm your endpoint and signature verification both work, before relying on it.
Related endpoints
- Create Monitor: Watch an X account for new posts and push them to your webhook(s).
- List Monitors: List every monitor on your account.
FAQ
What happens if I lose the signing secret?
It cannot be retrieved again through this or any other endpoint. The secret field is only ever populated in the response to the original POST webhook call, so if it is lost you need to delete the webhook and create a new one to get a fresh secret.
Why was my webhook rejected with an error about the URL?
The url parameter is validated before the webhook is created: private, loopback, link-local, and metadata IPs are refused. Point the endpoint at a publicly reachable HTTPS address rather than an internal or localhost address.
Delete Monitor DELETE
Soft-deletes the monitor: it stops polling immediately and disappears from List Monitors, but its delivery history is retained rather than cascade-deleted. Cost: Free per call.
List Webhooks GET
Returns every non-deleted webhook on your account. Never returns the signing secret; that is shown once, at creation. Cost: Free per call.