{"openapi":"3.1.0","info":{"title":"BulkAPIs","version":"1.0.0","description":"Social media automation API. Send DMs, schedule posts, manage automations, and track analytics — all via API. Built for SaaS integrations.","contact":{"url":"https://bulkapis.com"}},"servers":[{"url":"https://bulkapis.com","description":"Production"},{"url":"http://localhost:4000","description":"Local development"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key obtained from /api/v1/api-keys. Pass as `Authorization: Bearer bulk_ak_...`"}},"schemas":{"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object"}}},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"retryAfter":{"type":"string"}}}}},"Post":{"type":"object","properties":{"id":{"type":"string"},"accountId":{"type":"string"},"platform":{"type":"string","enum":["x"]},"content":{"type":"string"},"mediaUrls":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["draft","scheduled","queued","publishing","published","failed"]},"replyToPostId":{"type":"string","description":"Platform post ID to reply to (creates a reply tweet)"},"quotedPostId":{"type":"string","description":"Platform post ID to quote (creates a quote tweet)"},"idempotencyKey":{"type":"string","description":"Caller-provided dedup key. Duplicate requests return the original post."},"scheduledFor":{"type":"string","format":"date-time"},"publishedAt":{"type":"string","format":"date-time"},"platformPostId":{"type":"string"},"platformPostUrl":{"type":"string"}}},"AutomationRule":{"type":"object","properties":{"id":{"type":"string"},"accountId":{"type":"string"},"isActive":{"type":"boolean"},"triggerType":{"type":"string","enum":["keyword_comment","any_comment","mention"]},"triggerKeyword":{"type":"string"},"actionType":{"type":"string","enum":["send_dm"]},"actionTemplate":{"type":"string","description":"Supports {{username}} and {{comment}} placeholders"},"triggerCount":{"type":"integer"}}},"ConnectedAccount":{"type":"object","properties":{"id":{"type":"string"},"platform":{"type":"string"},"platformUserId":{"type":"string"},"username":{"type":"string"},"displayName":{"type":"string"},"isActive":{"type":"boolean"},"needsReauth":{"type":"boolean"}}}},"parameters":{"page":{"name":"page","in":"query","schema":{"type":"integer","default":1}},"limit":{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100}},"accountId":{"name":"accountId","in":"query","schema":{"type":"string"}}}},"paths":{"/api/v1/accounts":{"get":{"tags":["Accounts"],"summary":"List connected social accounts","operationId":"listAccounts","responses":{"200":{"description":"List of accounts"}}}},"/api/v1/accounts/{accountId}":{"get":{"tags":["Accounts"],"summary":"Get account details","operationId":"getAccount","parameters":[{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Account details"}}},"delete":{"tags":["Accounts"],"summary":"Disconnect account","operationId":"disconnectAccount","parameters":[{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Account disconnected"}}}},"/api/v1/accounts/{accountId}/health":{"get":{"tags":["Accounts"],"summary":"Check account health (token validity)","operationId":"checkAccountHealth","description":"Pings X API to verify the OAuth token is valid. Returns `healthy` (boolean) and `needsReauth` (boolean). If unhealthy, the account is flagged for re-authentication.","parameters":[{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Health status with `accountId`, `healthy`, `needsReauth`, `checkedAt`"}}}},"/api/v1/dm/send":{"post":{"tags":["DMs"],"summary":"Send a DM (text, media, or both)","operationId":"sendDm","description":"Sends a direct message synchronously. Returns the X conversation ID for the DM thread that was created or used. Supports cold DMs (new conversations) and existing conversations. Can include text, a media attachment (image/GIF/video), or both. Media is fetched from the provided URL, uploaded to X with the correct DM media category, and attached to the message.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accountId","recipientUserId"],"properties":{"accountId":{"type":"string","description":"Your connected account ID"},"recipientUserId":{"type":"string","description":"X user ID of the recipient"},"text":{"type":"string","maxLength":10000,"description":"Message text (required if no mediaUrl)"},"mediaUrl":{"type":"string","format":"uri","description":"Public URL of an image, GIF, or video to attach. Supported: JPEG, PNG, GIF, WEBP, MP4. Max 5MB for images, 15MB for GIFs, 512MB for video."},"idempotencyKey":{"type":"string","description":"Prevent duplicate sends"}}},"examples":{"textOnly":{"summary":"Text-only DM","value":{"accountId":"clxyz123","recipientUserId":"1234567890","text":"Hey! Thanks for the comment. Here's the link: https://example.com","idempotencyKey":"dm-user1234-campaign1"}},"withImage":{"summary":"DM with image","value":{"accountId":"clxyz123","recipientUserId":"1234567890","text":"Check out this product!","mediaUrl":"https://example.com/product.jpg"}},"mediaOnly":{"summary":"Media-only DM (no text)","value":{"accountId":"clxyz123","recipientUserId":"1234567890","mediaUrl":"https://example.com/promo.mp4"}}}}}},"responses":{"200":{"description":"DM sent successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"jobId":{"type":"string","description":"Unique reference ID for this send"},"status":{"type":"string","enum":["sent"],"description":"Always 'sent' on success"},"conversationId":{"type":"string","description":"X conversation ID for the DM thread"}}}}},"example":{"success":true,"data":{"jobId":"abc123","status":"sent","conversationId":"1234567890-9876543210"}}}}},"429":{"description":"Rate limited"}}}},"/api/v1/dm/send/bulk":{"post":{"tags":["DMs"],"summary":"Send DMs in bulk (text, media, or both)","operationId":"sendBulkDm","description":"Send up to 100 DMs in a single request. Each recipient can receive text, a media attachment, or both. Messages are staggered with configurable delay to avoid rate limits. Media URLs are fetched and uploaded to X per-message.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accountId","recipients"],"properties":{"accountId":{"type":"string"},"recipients":{"type":"array","maxItems":100,"items":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string"},"text":{"type":"string","description":"Message text (required if no mediaUrl)"},"mediaUrl":{"type":"string","format":"uri","description":"Public URL of media to attach (image, GIF, or video)"},"idempotencyKey":{"type":"string"}}}},"delayBetweenMs":{"type":"integer","default":2000,"description":"Delay between each DM (0-60000ms)"}}}}}},"responses":{"202":{"description":"Bulk DMs queued"}}}},"/api/v1/conversations":{"get":{"tags":["Inbox"],"summary":"List DM conversations","operationId":"listConversations","parameters":[{"name":"accountId","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["unread","read","archived"]}}],"responses":{"200":{"description":"List of conversations"}}}},"/api/v1/conversations/{conversationId}":{"get":{"tags":["Inbox"],"summary":"Get conversation details + messages","operationId":"getConversation","parameters":[{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation with messages"}}},"patch":{"tags":["Inbox"],"summary":"Update conversation status (read/archive)","operationId":"updateConversation","parameters":[{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["read","archived"]}}}}}},"responses":{"200":{"description":"Updated"}}}},"/api/v1/conversations/{conversationId}/messages":{"get":{"tags":["Inbox"],"summary":"List messages in a conversation","operationId":"listMessages","description":"Returns messages with both canonical fields (`content`, `sentAt`) and aliases (`text`, `createdAt`) for backward compatibility.","parameters":[{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}},{"name":"accountId","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100}},{"name":"cursor","in":"query","schema":{"type":"string","description":"Pagination cursor from previous response"}}],"responses":{"200":{"description":"Messages with `{ messages, pagination: { hasMore, nextCursor } }`"}}},"post":{"tags":["Inbox"],"summary":"Send a reply in an existing conversation (text, media, or both)","operationId":"sendConversationMessage","description":"Queues a DM reply for delivery to an existing conversation. Can include text, a media attachment, or both.","parameters":[{"name":"conversationId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accountId"],"properties":{"accountId":{"type":"string"},"text":{"type":"string","maxLength":10000,"description":"Message text (required if no mediaUrl)"},"mediaUrl":{"type":"string","format":"uri","description":"Public URL of media to attach (image, GIF, or video)"}}}}}},"responses":{"202":{"description":"Message queued for delivery"}}}},"/api/v1/posts":{"get":{"tags":["Posts"],"summary":"List posts","operationId":"listPosts","parameters":[{"name":"accountId","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","scheduled","published","failed"]}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"List of posts"}}},"post":{"tags":["Posts"],"summary":"Create a post","operationId":"createPost","description":"Create a draft, schedule for later, or publish immediately. Supports replies (`replyToPostId`) and quote tweets (`quotedPostId`). Use `idempotencyKey` to prevent duplicate posts in retry scenarios. Media URLs are downloaded and uploaded to X automatically.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accountId","content"],"properties":{"accountId":{"type":"string"},"content":{"type":"string","maxLength":25000},"mediaUrls":{"type":"array","items":{"type":"string"},"maxItems":4,"description":"Up to 4 media URLs. BulkAPIs downloads and uploads to X for you."},"status":{"type":"string","enum":["draft","scheduled","published"],"default":"published"},"scheduledFor":{"type":"string","format":"date-time"},"queue":{"type":"boolean","description":"Auto-schedule using next available slot"},"replyToPostId":{"type":"string","description":"Platform post ID to reply to (X: in_reply_to_tweet_id)"},"quotedPostId":{"type":"string","description":"Platform post ID to quote (X: quote_tweet_id)"},"idempotencyKey":{"type":"string","maxLength":255,"description":"Prevents duplicate posts. If a post with this key exists, returns the existing post."}}},"example":{"accountId":"clxyz123","content":"Just shipped our new API! Check it out at bulkapis.com","replyToPostId":"1234567890","idempotencyKey":"campaign-abc-post-1"}}}},"responses":{"200":{"description":"Deduplicated — existing post returned"},"201":{"description":"Post created"}}}},"/api/v1/posts/{postId}":{"get":{"tags":["Posts"],"summary":"Get post details + metrics","operationId":"getPost","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Post with latest metrics"}}},"put":{"tags":["Posts"],"summary":"Update post content or schedule","operationId":"updatePost","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Post updated"}}},"delete":{"tags":["Posts"],"summary":"Delete post (also deletes from platform if published)","operationId":"deletePost","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Post deleted"}}}},"/api/v1/posts/{postId}/retry":{"post":{"tags":["Posts"],"summary":"Retry a failed post","operationId":"retryPost","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Post re-queued"}}}},"/api/v1/posts/{postId}/publish":{"post":{"tags":["Posts"],"summary":"Publish a draft/scheduled post immediately","operationId":"publishPost","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Post queued for immediate publishing"}}}},"/api/v1/automations":{"get":{"tags":["Automations"],"summary":"List automation rules","operationId":"listAutomations","responses":{"200":{"description":"List of automation rules"}}},"post":{"tags":["Automations"],"summary":"Create an automation rule","operationId":"createAutomation","description":"Create a rule that triggers an action (e.g., send DM) when someone comments on your posts. Perfect for comment-to-DM lead magnet funnels.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accountId","actionTemplate"],"properties":{"accountId":{"type":"string"},"triggerType":{"type":"string","enum":["keyword_comment","any_comment","mention"],"default":"keyword_comment"},"triggerKeyword":{"type":"string","description":"Comma-separated keywords to match"},"actionType":{"type":"string","enum":["send_dm"],"default":"send_dm"},"actionTemplate":{"type":"string","description":"DM template. Use {{username}} and {{comment}} placeholders."},"postId":{"type":"string","description":"Monitor a specific post (optional)"},"postUrl":{"type":"string"}}},"example":{"accountId":"clxyz123","triggerType":"keyword_comment","triggerKeyword":"link,send,interested","actionTemplate":"Hey {{username}}! Here's the link you asked for: https://example.com"}}}},"responses":{"201":{"description":"Automation created"}}}},"/api/v1/automations/{automationId}":{"get":{"tags":["Automations"],"summary":"Get automation rule details","operationId":"getAutomation","parameters":[{"name":"automationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Automation details with recent logs"}}},"put":{"tags":["Automations"],"summary":"Update automation rule","operationId":"updateAutomation","parameters":[{"name":"automationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Automations"],"summary":"Delete automation rule","operationId":"deleteAutomation","parameters":[{"name":"automationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/api/v1/automations/{automationId}/logs":{"get":{"tags":["Automations"],"summary":"List automation execution logs","operationId":"listAutomationLogs","parameters":[{"name":"automationId","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}},{"name":"status","in":"query","schema":{"type":"string","enum":["triggered","dm_sent","dm_failed","skipped"]}}],"responses":{"200":{"description":"Paginated logs"}}}},"/api/v1/comments/recent":{"get":{"tags":["Comments"],"summary":"Get recent comments/mentions for an account","operationId":"getRecentComments","description":"Fetches recent mentions from X API (live, not cached). Supports `sinceDate` for windowed fetching (maps to X API `start_time`, max 7 days back). Rate limit: 60 req/min.","parameters":[{"name":"accountId","in":"query","required":true,"schema":{"type":"string"}},{"name":"sinceDate","in":"query","schema":{"type":"string","format":"date-time","description":"ISO 8601 date. Only return mentions after this time (max 7 days back)."}},{"name":"paginationToken","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":100}}],"responses":{"200":{"description":"Comments with pagination"}}}},"/api/v1/comments/{postId}":{"get":{"tags":["Comments"],"summary":"Get comments on a specific post","operationId":"getPostComments","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"accountId","in":"query","required":true,"schema":{"type":"string"}},{"name":"paginationToken","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Comments on the post"}}},"post":{"tags":["Comments"],"summary":"Reply to a post (create a reply tweet)","operationId":"replyToPost","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accountId","text"],"properties":{"accountId":{"type":"string"},"text":{"type":"string","maxLength":280}}}}}},"responses":{"201":{"description":"Reply created"}}}},"/api/v1/comments/inbox":{"get":{"tags":["Comments"],"summary":"List detected comments and mentions (cached)","operationId":"listCommentInbox","parameters":[{"name":"accountId","in":"query","schema":{"type":"string"}},{"name":"automationId","in":"query","schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Paginated comment inbox"}}}},"/api/v1/media":{"get":{"tags":["Media"],"summary":"List uploaded media","operationId":"listMedia","parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["pending","ready","expired"]}},{"name":"page","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Paginated media list"}}}},"/api/v1/media/upload":{"post":{"tags":["Media"],"summary":"Initialize a media upload","operationId":"initMediaUpload","description":"Step 1: Get an upload ID. Step 2: Upload the file to the returned URL. Step 3: Use the media ID in your post.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["filename","contentType"],"properties":{"filename":{"type":"string"},"contentType":{"type":"string","enum":["image/jpeg","image/png","image/gif","image/webp","video/mp4","video/quicktime"]},"sizeBytes":{"type":"integer"}}}}}},"responses":{"201":{"description":"Upload initialized with ID and URL"}}}},"/api/v1/media/{mediaId}":{"get":{"tags":["Media"],"summary":"Check media upload status","operationId":"getMedia","parameters":[{"name":"mediaId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Media status"}}}},"/api/v1/media/{mediaId}/upload":{"post":{"tags":["Media"],"summary":"Complete a media upload","operationId":"completeMediaUpload","parameters":[{"name":"mediaId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"publicUrl":{"type":"string","description":"Hosted URL of the uploaded file"},"sourceUrl":{"type":"string","description":"URL to fetch the file from"}}}}}},"responses":{"200":{"description":"Upload completed"}}}},"/api/v1/analytics/posts":{"get":{"tags":["Analytics"],"summary":"Get post engagement analytics","operationId":"getPostAnalytics","parameters":[{"name":"accountId","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Posts with engagement metrics"}}}},"/api/v1/analytics/accounts/{accountId}":{"get":{"tags":["Analytics"],"summary":"Get account follower growth","operationId":"getAccountAnalytics","parameters":[{"name":"accountId","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","default":30}}],"responses":{"200":{"description":"Follower growth data"}}}},"/api/v1/analytics/best-time":{"get":{"tags":["Analytics"],"summary":"Get recommended posting times","operationId":"getBestTimeToPost","parameters":[{"name":"accountId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Best hours and days to post"}}}},"/api/v1/schedules":{"get":{"tags":["Schedules"],"summary":"List schedule slots","operationId":"listSchedules","responses":{"200":{"description":"Schedule slots"}}},"post":{"tags":["Schedules"],"summary":"Create a schedule slot","operationId":"createSchedule","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["accountId","name","timezone","slots"],"properties":{"accountId":{"type":"string"},"name":{"type":"string"},"timezone":{"type":"string","example":"America/New_York"},"slots":{"type":"array","items":{"type":"object","properties":{"day":{"type":"integer","minimum":0,"maximum":6,"description":"0=Sun, 6=Sat"},"hour":{"type":"integer","minimum":0,"maximum":23},"minute":{"type":"integer","minimum":0,"maximum":59}}}}}}}}},"responses":{"201":{"description":"Schedule created"}}}},"/api/v1/schedules/{scheduleId}":{"get":{"tags":["Schedules"],"summary":"Get schedule with upcoming slot previews","operationId":"getSchedule","parameters":[{"name":"scheduleId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Schedule with upcoming times"}}},"put":{"tags":["Schedules"],"summary":"Update schedule","operationId":"updateSchedule","parameters":[{"name":"scheduleId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Schedules"],"summary":"Delete schedule","operationId":"deleteSchedule","parameters":[{"name":"scheduleId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/api/v1/schedules/next-slot":{"get":{"tags":["Schedules"],"summary":"Get next available posting slot","operationId":"getNextSlot","parameters":[{"name":"accountId","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Next slot time with conflict info"}}}},"/api/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","operationId":"listWebhooks","responses":{"200":{"description":"Webhooks"}}},"post":{"tags":["Webhooks"],"summary":"Create webhook","operationId":"createWebhook","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","url","events"],"properties":{"name":{"type":"string"},"url":{"type":"string","format":"uri"},"secret":{"type":"string","description":"Used to sign payloads with HMAC-SHA256"},"events":{"type":"array","items":{"type":"string","enum":["dm.received","dm.sent","dm.failed","post.published","post.scheduled","post.failed","post.deleted","comment.received","mention.received","automation.triggered","ai.task.completed","ai.task.failed","credits.low","webhook.test"]}}}}}}},"responses":{"201":{"description":"Webhook created"}}}},"/api/v1/webhooks/{webhookId}":{"get":{"tags":["Webhooks"],"summary":"Get webhook details","operationId":"getWebhook","parameters":[{"name":"webhookId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook details"}}},"put":{"tags":["Webhooks"],"summary":"Update webhook","operationId":"updateWebhook","parameters":[{"name":"webhookId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Webhooks"],"summary":"Delete webhook","operationId":"deleteWebhook","parameters":[{"name":"webhookId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/api/v1/webhooks/{webhookId}/test":{"post":{"tags":["Webhooks"],"summary":"Send a test webhook event","operationId":"testWebhook","description":"Sends a `webhook.test` event to the webhook URL. The payload includes `event: 'webhook.test'` and a `timestamp`.","parameters":[{"name":"webhookId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Test result with status code and response"}}}},"/api/v1/webhooks/{webhookId}/logs":{"get":{"tags":["Webhooks"],"summary":"List webhook delivery logs","operationId":"listWebhookLogs","parameters":[{"name":"webhookId","in":"path","required":true,"schema":{"type":"string"}},{"name":"success","in":"query","schema":{"type":"boolean"}},{"name":"page","in":"query","schema":{"type":"integer"}},{"name":"limit","in":"query","schema":{"type":"integer"}}],"responses":{"200":{"description":"Delivery logs"}}}},"/api/v1/api-keys":{"get":{"tags":["API Keys"],"summary":"List API keys","operationId":"listApiKeys","responses":{"200":{"description":"API keys (hashed, no raw values)"}}},"post":{"tags":["API Keys"],"summary":"Create API key","operationId":"createApiKey","description":"Returns the raw key ONCE. Store it securely — it cannot be retrieved again.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}}}}}},"responses":{"201":{"description":"Key created (includes raw key)"}}}},"/api/v1/api-keys/{keyId}":{"get":{"tags":["API Keys"],"summary":"Get API key details","operationId":"getApiKey","parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key details"}}},"patch":{"tags":["API Keys"],"summary":"Update API key name or expiry","operationId":"updateApiKey","parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["API Keys"],"summary":"Revoke API key","operationId":"deleteApiKey","parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Revoked"}}}},"/api/v1/usage":{"get":{"tags":["Usage & Billing"],"summary":"Get current plan and usage","operationId":"getUsage","responses":{"200":{"description":"Plan details and current usage"}}}},"/api/v1/usage/history":{"get":{"tags":["Usage & Billing"],"summary":"Get usage over time","operationId":"getUsageHistory","parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":30,"maximum":90}},{"name":"endpoint","in":"query","schema":{"type":"string"}},{"name":"platform","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Daily usage aggregation"}}}},"/api/v1/x/intel/estimate":{"get":{"tags":["X Intelligence"],"summary":"Get pricing table for all X Intel endpoints","operationId":"getXIntelPricing","responses":{"200":{"description":"Full pricing table with per-unit costs and notes"}}},"post":{"tags":["X Intelligence"],"summary":"Estimate the cost of a planned X Intel call","operationId":"estimateXIntelCost","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["endpoint","units"],"properties":{"endpoint":{"type":"string","description":"The X Intel endpoint key, e.g. 'search_recent'"},"units":{"type":"integer","minimum":0,"maximum":500000}}}}}},"responses":{"200":{"description":"Cost estimate including balance_after + affordable flag"}}}},"/api/v1/x/intel/search/recent":{"post":{"tags":["X Intelligence"],"summary":"Search X posts from the last 7 days","description":"Full-text search over X's recent index. Up to 100 results per call. 60-second response cache. Billed at 1.15 credits/post returned (15% markup on X's $0.005/post upstream).\n\n**Viral filtering** — X's `min_faves:`, `min_retweets:`, `min_replies:` operators are enterprise-only and unavailable under pay-per-use. Use the `min_likes`/`min_reposts`/`min_replies`/`min_impressions`/`min_author_followers` params instead — BulkAPIs pulls the widest upstream window and filters server-side. **Billing is based on the upstream pull (up to max_results), not the filtered result count.**\n\n**Media** — every response includes resolved media URLs (photos, video thumbnails, durations, alt text) via X expansions. No extra credit cost.","operationId":"xIntelSearchRecent","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","maxLength":512,"description":"X search operator string, e.g. 'AI SaaS lang:en -is:retweet'"},"max_results":{"type":"integer","minimum":10,"maximum":100,"default":100},"next_token":{"type":"string"},"since_id":{"type":"string"},"until_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time"},"sort_order":{"type":"string","enum":["recency","relevancy"],"description":"When any min_* filter is set and this is omitted, defaults to 'relevancy' to maximize high-engagement hits."},"min_likes":{"type":"integer","minimum":0,"description":"Filter: only posts with like_count >= N"},"min_reposts":{"type":"integer","minimum":0,"description":"Filter: only posts with retweet_count >= N"},"min_replies":{"type":"integer","minimum":0,"description":"Filter: only posts with reply_count >= N"},"min_quotes":{"type":"integer","minimum":0},"min_bookmarks":{"type":"integer","minimum":0},"min_impressions":{"type":"integer","minimum":0},"min_author_followers":{"type":"integer","minimum":0,"description":"Filter: only posts whose author has >= N followers"},"require_media":{"type":"boolean","description":"Filter: only posts with attached media (photo/video/gif)"},"exclude_replies":{"type":"boolean","description":"Filter: drop posts that are replies (X's -is:reply is also supported in query)"}}}}}},"responses":{"200":{"description":"Posts matching the query + any min_* filters. Response includes `filter.prefilter_count`, `filter.filtered_count`, `includes.users`, `includes.media`."}}}},"/api/v1/x/intel/search/viral":{"post":{"tags":["X Intelligence"],"summary":"Viral-rank search with auto-pagination + cache","description":"Solves X's recency-bias on /search/recent (page 1 of relevancy-sorted results often lacks the highest-engagement posts).\n\n**Strategy:**\n1. **Cache (FREE)** — if the caller has an active viral-watch with rules overlapping the query, returns top-scored recent hits first. Zero X credits.\n2. **Paginate + sort** — pulls up to `depth_pages` pages (default 3 = 300 posts) from /search/recent with sort_order=relevancy, applies filters, engagement-sorts the union, returns top N.\n\n**Cost model:** cache hits are free. Upstream pulls are billed at 1.15 credits/post × posts_scanned (dedup applies for same-UTC-day repeats). A 3-page pull with no cache hits = ~345 credits (~$1.72 at retail). Response includes `cost_per_additional_page` so the caller can decide whether to go deeper.\n\nEvery returned post carries `engagement_score` + `rank` — pre-sorted, ready to render as a leaderboard.","operationId":"xIntelSearchViral","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","maxLength":512},"depth_pages":{"type":"integer","minimum":1,"maximum":5,"default":3,"description":"Number of 100-post pages to scan when cache is insufficient. Hard-capped at 5 (500 posts = 575 credits)."},"top":{"type":"integer","minimum":1,"maximum":100,"default":25},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time"},"use_watch_cache":{"type":"boolean","default":true,"description":"Set false to force a fresh upstream pull even when caller has overlapping viral-watches."},"min_likes":{"type":"integer","minimum":0},"min_reposts":{"type":"integer","minimum":0},"min_replies":{"type":"integer","minimum":0},"min_quotes":{"type":"integer","minimum":0},"min_bookmarks":{"type":"integer","minimum":0},"min_impressions":{"type":"integer","minimum":0},"min_author_followers":{"type":"integer","minimum":0},"require_media":{"type":"boolean"},"exclude_replies":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Engagement-ranked posts with source_breakdown showing cache_hits vs. upstream_posts_scanned, pages_pulled, next_page_token, and cost_per_additional_page."}}}},"/api/v1/x/intel/search/archive":{"post":{"tags":["X Intelligence"],"summary":"Search the full X archive (back to 2006)","description":"Growth plan or higher. Up to 500 results per call. Billed at 2 credits/post returned.\n\nAll viral-filter params supported (see /search/recent description). When any filter is set, defaults to pulling the full 500-result window upstream for max post-filter survival.","operationId":"xIntelSearchArchive","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","maxLength":1024},"max_results":{"type":"integer","minimum":10,"maximum":500,"default":500},"next_token":{"type":"string"},"since_id":{"type":"string"},"until_id":{"type":"string"},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time"},"sort_order":{"type":"string","enum":["recency","relevancy"]},"min_likes":{"type":"integer","minimum":0},"min_reposts":{"type":"integer","minimum":0},"min_replies":{"type":"integer","minimum":0},"min_quotes":{"type":"integer","minimum":0},"min_bookmarks":{"type":"integer","minimum":0},"min_impressions":{"type":"integer","minimum":0},"min_author_followers":{"type":"integer","minimum":0},"require_media":{"type":"boolean"},"exclude_replies":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Historical posts matching the query"},"403":{"description":"Requires Growth plan"}}}},"/api/v1/x/intel/counts/recent":{"post":{"tags":["X Intelligence"],"summary":"Get post volume over time (last 7 days)","description":"Flat-priced at 5 credits/call.","operationId":"xIntelCountsRecent","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","maxLength":1024},"granularity":{"type":"string","enum":["minute","hour","day"],"default":"hour"},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time"}}}}}},"responses":{"200":{"description":"Array of count buckets + total"}}}},"/api/v1/x/intel/counts/all":{"post":{"tags":["X Intelligence"],"summary":"Get historical post volume (full archive)","description":"Growth plan or higher. Flat-priced at 10 credits/call.","operationId":"xIntelCountsAll","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","maxLength":1024},"granularity":{"type":"string","enum":["minute","hour","day"],"default":"day"},"start_time":{"type":"string","format":"date-time"},"end_time":{"type":"string","format":"date-time"},"next_token":{"type":"string"}}}}}},"responses":{"200":{"description":"Historical count buckets"},"403":{"description":"Requires Growth plan"}}}},"/api/v1/x/intel/posts/hydrate":{"post":{"tags":["X Intelligence"],"summary":"Hydrate post metrics by ID (batch up to 100)","description":"Re-reads posts to refresh public_metrics. **Dedup: repeat reads of the same post within the same UTC day are served from cache and cost 0 credits.** This is the engine of velocity tracking — poll candidates hourly for near-zero marginal cost.","operationId":"xIntelHydratePosts","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":100}}}}}},"responses":{"200":{"description":"Posts with current metrics + cached_count/fetched_count"}}}},"/api/v1/x/intel/posts/{postId}/liking-users":{"get":{"tags":["X Intelligence"],"summary":"Users who liked a post (0.2 credits/user, min 1)","operationId":"xIntelLikingUsers","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_results","in":"query","schema":{"type":"integer","minimum":10,"maximum":100,"default":100}},{"name":"pagination_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Users array + next_token"}}}},"/api/v1/x/intel/posts/{postId}/retweeted-by":{"get":{"tags":["X Intelligence"],"summary":"Users who reposted a post (0.2 credits/user)","operationId":"xIntelRetweetedBy","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_results","in":"query","schema":{"type":"integer","minimum":10,"maximum":100,"default":100}},{"name":"pagination_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Users array + next_token"}}}},"/api/v1/x/intel/posts/{postId}/quote-tweets":{"get":{"tags":["X Intelligence"],"summary":"Quote posts of a post (1.15 credits/post)","operationId":"xIntelQuoteTweets","parameters":[{"name":"postId","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_results","in":"query","schema":{"type":"integer","minimum":10,"maximum":100,"default":100}},{"name":"pagination_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Posts with includes.users"}}}},"/api/v1/x/intel/users/by-username/{username}":{"get":{"tags":["X Intelligence"],"summary":"Resolve a username to a full user object (0.2 credits, dedup 24h UTC)","operationId":"xIntelUserByUsername","parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string"},"description":"@ prefix optional"}],"responses":{"200":{"description":"User object with public_metrics"},"404":{"description":"User not found"}}}},"/api/v1/x/intel/users/lookup":{"post":{"tags":["X Intelligence"],"summary":"Batch-lookup users by IDs and/or usernames (up to 100)","description":"0.2 credits/user, cached per UTC day.","operationId":"xIntelUserLookup","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string"},"maxItems":100},"usernames":{"type":"array","items":{"type":"string"},"maxItems":100}}}}}},"responses":{"200":{"description":"Users array + cached_count/fetched_count"}}}},"/api/v1/x/intel/users/{userId}/posts":{"get":{"tags":["X Intelligence"],"summary":"Get a creator's recent posts (creator study)","description":"1.15 credits/post returned.","operationId":"xIntelUserPosts","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_results","in":"query","schema":{"type":"integer","minimum":5,"maximum":100,"default":100}},{"name":"pagination_token","in":"query","schema":{"type":"string"}},{"name":"since_id","in":"query","schema":{"type":"string"}},{"name":"until_id","in":"query","schema":{"type":"string"}},{"name":"exclude","in":"query","schema":{"type":"string","description":"Comma-separated: 'retweets,replies'"}},{"name":"start_time","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"end_time","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Posts + includes.users + next_token"}}}},"/api/v1/x/intel/users/{userId}/followers":{"get":{"tags":["X Intelligence"],"summary":"Get a user's followers (0.2 credits/user)","operationId":"xIntelUserFollowers","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_results","in":"query","schema":{"type":"integer","minimum":10,"maximum":100,"default":100}},{"name":"pagination_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Users array + next_token"}}}},"/api/v1/x/intel/users/{userId}/following":{"get":{"tags":["X Intelligence"],"summary":"Get who a user follows (0.2 credits/user)","operationId":"xIntelUserFollowing","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"max_results","in":"query","schema":{"type":"integer","minimum":10,"maximum":100,"default":100}},{"name":"pagination_token","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Users array + next_token"}}}},"/api/v1/x/intel/trends/{woeid}":{"get":{"tags":["X Intelligence"],"summary":"Get X's trending topics by location (2 credits/call)","description":"WOEID = Yahoo 'Where On Earth ID'. 1 = worldwide, 23424977 = USA, 23424975 = UK.","operationId":"xIntelTrends","parameters":[{"name":"woeid","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Trends array"}}}},"/api/v1/x/intel/viral-watch":{"get":{"tags":["X Intelligence — Viral Watch"],"summary":"List viral watches","operationId":"listViralWatches","responses":{"200":{"description":"Array of watches with captured-hit counts"}}},"post":{"tags":["X Intelligence — Viral Watch"],"summary":"Create a viral watch","description":"Creates a managed X filtered-stream rule set. BulkAPIs pools rules across all watches onto a single connection. Captured hits are billed 2 credits/hit. Requires Base plan (3 watches), Growth (10), or Scale (50).","operationId":"createViralWatch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","rules"],"properties":{"name":{"type":"string","minLength":1,"maxLength":80},"rules":{"type":"array","minItems":1,"maxItems":5,"items":{"type":"string","minLength":2,"maxLength":900},"description":"X search operator strings. Will be composed with filters."},"filters":{"type":"object","properties":{"min_faves":{"type":"integer","minimum":0},"min_reposts":{"type":"integer","minimum":0},"min_replies":{"type":"integer","minimum":0},"min_author_followers":{"type":"integer","minimum":0},"languages":{"type":"array","items":{"type":"string","minLength":2,"maxLength":2}},"exclude_retweets":{"type":"boolean"},"exclude_replies":{"type":"boolean"},"exclude_quotes":{"type":"boolean"}}},"hydrate_interval":{"type":"string","enum":["15m","1h","6h","24h"],"default":"1h"},"hydrate_window_hours":{"type":"integer","minimum":1,"maximum":168,"default":48},"score_formula":{"type":"string","enum":["velocity","like_per_follower","impressions_per_hour"],"default":"velocity"},"webhook_url":{"type":"string","format":"uri"},"daily_hit_cap":{"type":"integer","minimum":10,"maximum":10000,"default":500}}}}}},"responses":{"201":{"description":"Created watch"},"403":{"description":"Plan limit or gating"}}}},"/api/v1/x/intel/viral-watch/{watchId}":{"get":{"tags":["X Intelligence — Viral Watch"],"summary":"Get a viral watch","operationId":"getViralWatch","parameters":[{"name":"watchId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Watch"},"404":{"description":"Not found"}}},"patch":{"tags":["X Intelligence — Viral Watch"],"summary":"Update a viral watch (partial)","operationId":"updateViralWatch","parameters":[{"name":"watchId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated watch"}}},"delete":{"tags":["X Intelligence — Viral Watch"],"summary":"Delete a viral watch","operationId":"deleteViralWatch","parameters":[{"name":"watchId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/api/v1/x/intel/viral-watch/{watchId}/hits":{"get":{"tags":["X Intelligence — Viral Watch"],"summary":"List captured hits for a watch","operationId":"listViralWatchHits","parameters":[{"name":"watchId","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":100}},{"name":"lifecycle","in":"query","schema":{"type":"string","enum":["new","rising","peak","decaying","stale"]}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"sort","in":"query","schema":{"type":"string","enum":["score","captured_at"],"default":"score"}}],"responses":{"200":{"description":"Paginated hits"}}}},"/api/v1/x/intel/viral-watch/{watchId}/leaderboard":{"get":{"tags":["X Intelligence — Viral Watch"],"summary":"Top-N ranked hits within a time window","description":"The primary 'what is going viral right now' endpoint. Ranks by score (see watch.score_formula).","operationId":"getViralWatchLeaderboard","parameters":[{"name":"watchId","in":"path","required":true,"schema":{"type":"string"}},{"name":"window_hours","in":"query","schema":{"type":"integer","default":24,"minimum":1,"maximum":168}},{"name":"top","in":"query","schema":{"type":"integer","default":25,"maximum":100}},{"name":"lifecycle","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Ranked leaderboard"}}}}},"tags":[{"name":"Accounts","description":"Manage connected social accounts"},{"name":"DMs","description":"Send direct messages — including cold DMs to new conversations"},{"name":"Inbox","description":"DM inbox — list conversations, read messages"},{"name":"Posts","description":"Create, schedule, and manage social media posts"},{"name":"Automations","description":"Comment-triggered auto-DMs (ManyChat/Hypefury style)"},{"name":"Comments","description":"Comment and mention inbox"},{"name":"Media","description":"Upload and manage media for posts"},{"name":"Analytics","description":"Post engagement and follower growth analytics"},{"name":"Schedules","description":"Time slot scheduling for auto-posting"},{"name":"Webhooks","description":"Real-time event notifications. Events: dm.received, dm.sent, dm.failed, post.*, comment.received, mention.received, automation.triggered, ai.task.*, credits.low, viral_watch.hit.created, viral_watch.hit.scored, webhook.test. Payloads are HMAC-SHA256 signed."},{"name":"API Keys","description":"Manage API authentication keys"},{"name":"Usage & Billing","description":"Plan limits and usage tracking"},{"name":"X Intelligence","description":"Viral-content discovery on X/Twitter. Search, hydrate, creator-study, trends. Billed per-post (1.15 credits = $0.005 upstream + 15%) with 24h UTC dedup for free repeat reads."},{"name":"X Intelligence — Viral Watch","description":"Managed filtered-stream watches. Define rules + filters, BulkAPIs pools them onto a single X stream connection, captures matching posts, hydrates metrics on a schedule, scores by velocity, and emits webhooks when scores cross thresholds."}]}