TwitterAPIs Docs
API ReferenceMonitoring

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.

POST
/webhook

Authorization

bearerAuth
AuthorizationBearer <token>

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

UnitPrice
Per callFree

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.
  • 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.