Getting Started
The Scrapely API allows you to send direct messages and fetch conversations programmatically. Use it to integrate Twitter DM automation into your own applications and workflows.
Base URL
https://app.scrapely.co/api/v1Available Endpoints
/accountsList your Twitter accounts/accountsAdd a new account/accountsRemove an account/accounts/cookiesUpdate account cookies/get-cookiesQueue cookie extraction job/get-cookies/statusCheck extraction status/scraping-sourcesCreate a scraping source/scraping-sourcesList/check scraping status/campaignsLaunch a DM campaign/campaignsList campaigns/campaigns/analyticsGet campaign analytics/conversationsFetch conversations/dm/sendSend a direct message/crm/conversationsGet CRM conversations by tag/crm/updateUpdate CRM data/scheduled-tweetsSchedule a tweet/scheduled-tweetsList scheduled tweets/scheduled-tweetsCancel scheduled tweetQuick Start
1. Generate an API key from your Settings page
2. Make your first API call:
curl -H "X-API-Key: YOUR_API_KEY" \
https://app.scrapely.co/api/v1/accountsOpenAPI Specification
Download our OpenAPI spec to generate typed clients for any language:
# Generate TypeScript client
npx openapi-typescript-codegen --input https://app.scrapely.co/openapi.yaml --output ./api
# Generate Python client
pip install openapi-python-client
openapi-python-client generate --url https://app.scrapely.co/openapi.yaml
# Import into Postman
# File -> Import -> Link -> https://app.scrapely.co/openapi.yamlAuthentication
All API requests require authentication using an API key. Generate API keys from your Settings page.
X-API-Key Header (Recommended)
curl -H "X-API-Key: sk_live_your_api_key" \
https://app.scrapely.co/api/v1/accountsAuthorization Bearer Header
curl -H "Authorization: Bearer sk_live_your_api_key" \
https://app.scrapely.co/api/v1/accountsNever expose your API key in client-side code or public repositories.
List Accounts
/accountsList your connected Twitter accountsReturns a list of all active Twitter accounts. Use the account id when sending DMs.
Request
curl -H "X-API-Key: YOUR_API_KEY" \
https://app.scrapely.co/api/v1/accountsResponse
{
"accounts": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"handle": "yourhandle",
"name": "Your Name",
"profile_image_url": "https://pbs.twimg.com/...",
"is_active": true,
"is_verified": true,
"dms_sent": 1250,
"created_at": "2024-01-15T10:30:00Z",
"cookies": [
{ "name": "auth_token", "value": "abc123...", "domain": ".x.com" },
{ "name": "ct0", "value": "xyz789...", "domain": ".x.com" }
],
"proxy": "161.77.187.46:12323",
"proxy_auth": "username:password",
"is_paused": false,
"followups_paused": false,
"warmup_paused": false,
"ai_setter_enabled": true
}
]
}Response Fields
| Field | Type | Description |
|---|---|---|
| is_paused | boolean | Whether DM sending is paused for this account |
| followups_paused | boolean | Whether follow-up messages are paused |
| warmup_paused | boolean | Whether account warmup is paused |
| ai_setter_enabled | boolean | Whether AI setter is enabled for this account |
Add Account
/accountsAdd a new Twitter accountAdd a new Twitter account to your workspace. Requires cookies exported from your browser and a proxy configuration.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| handle | string | Required | Twitter handle (with or without @) |
| cookies | array | Required | Array of cookie objects (Chrome export format) |
| proxy | string | Required | Proxy URL (e.g., http://proxy.example.com:8080) |
| proxy_auth | string | Required | Proxy authentication (username:password) |
| xchat_pin | string | Required | X chat PIN code |
Request
curl -X POST \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"handle": "myhandle",
"cookies": [
{"name": "ct0", "value": "abc123...", "domain": ".twitter.com"},
{"name": "auth_token", "value": "xyz789...", "domain": ".twitter.com"}
],
"proxy": "http://proxy.example.com:8080",
"proxy_auth": "username:password",
"xchat_pin": "123456"
}' \
https://app.scrapely.co/api/v1/accountsResponse
{
"success": true,
"message": "Account created successfully",
"account": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"handle": "myhandle",
"is_active": true,
"created_at": "2024-01-15T10:30:00Z",
"is_new": true
}
}Cookies must include at minimum ct0 and auth_token. Use a browser extension like "EditThisCookie" to export cookies from Twitter.
Remove Account
/accountsRemove a Twitter accountRemove a Twitter account from your workspace. You can identify the account by either its UUID or Twitter handle.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| account_id | string | Required* | The account UUID to remove |
| handle | string | Required* | Twitter handle to remove (with or without @) |
*Either account_id or handle is required.
Request (by ID)
curl -X DELETE \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"account_id": "550e8400-e29b-41d4-a716-446655440000"
}' \
https://app.scrapely.co/api/v1/accountsRequest (by Handle)
curl -X DELETE \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"handle": "myhandle"
}' \
https://app.scrapely.co/api/v1/accountsResponse
{
"success": true,
"message": "Account removed successfully",
"account": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"handle": "myhandle"
}
}Removing an account will permanently delete it from your workspace. All associated data including DM history will be retained, but the account will no longer be available for sending messages.
Create Scraping Source
/scraping-sourcesCreate a new lead source by scraping TwitterCreate a lead source by scraping followers and/or following from Twitter accounts. Credits are consumed based on the number of leads scraped.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Required | Name for the lead source |
| sources | array | Required | Array of scraping targets |
| filters | object | Optional | Filter configuration to filter scraped leads |
Source Object
| Parameter | Type | Description |
|---|---|---|
| handle | string | Twitter handle to scrape |
| followers | boolean | Scrape followers |
| following | boolean | Scrape following |
All followers/following will be scraped automatically. Credits are deducted as leads are imported.
Filters Object
Apply filters to scraped leads in real-time during the scraping process. Only leads matching your filter criteria will be saved and count against your credits.
| Parameter | Type | Description |
|---|---|---|
| includeKeywords | array | Array of keyword groups. Each group is an array of keywords. Leads must match keywords in their bio/description. |
| excludeKeywords | array | Array of keyword groups to exclude. Leads matching these keywords will be filtered out. |
| includeWithinLogic | string | "AND" or "OR". Logic within each include keyword group. Default: "AND" |
| includeBetweenLogic | string | "AND" or "OR". Logic between include keyword groups. Default: "OR" |
| excludeWithinLogic | string | "AND" or "OR". Logic within each exclude keyword group. Default: "AND" |
| excludeBetweenLogic | string | "AND" or "OR". Logic between exclude keyword groups. Default: "OR" |
| locationExcludeKeywords | array | Array of location keywords to exclude (e.g., country names). |
| followers | object | { min: number, max: number }. Only keep leads who have this many followers themselves. |
| following | object | { min: number, max: number }. Only keep leads who are following this many accounts. |
| hasWebsite | boolean | true = only leads with website, false = only leads without website, null = no filter. |
Request
curl -X POST \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Tech Founders Q1",
"sources": [
{
"handle": "paulg",
"followers": true
},
{
"handle": "naval",
"followers": true,
"following": true
}
],
"filters": {
"includeKeywords": [["founder", "ceo"], ["startup"]],
"includeBetweenLogic": "OR",
"includeWithinLogic": "AND",
"excludeKeywords": [["hiring", "recruiter"]],
"followers": { "min": 100, "max": 50000 },
"hasWebsite": true
}
}' \
https://app.scrapely.co/api/v1/scraping-sourcesResponse
{
"success": true,
"lead_source_id": "uuid-here",
"name": "Tech Founders Q1",
"jobs_created": 3,
"message": "Scraping all followers/following. Credits deducted as leads are imported.",
"jobs": [
{
"id": "job-uuid-1",
"type": "followers",
"handle": "paulg",
"status": "pending"
},
{
"id": "job-uuid-2",
"type": "followers",
"handle": "naval",
"status": "pending"
},
{
"id": "job-uuid-3",
"type": "following",
"handle": "naval",
"status": "pending"
}
]
}Check Scraping Status
/scraping-sourcesList scraping sources or get statusCheck the status of your scraping jobs. Pass an id parameter to get detailed status for a specific source.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| id | string | Get specific source by ID |
| limit | number | Results per page (default: 20, max: 100) |
| offset | number | Pagination offset |
Request
curl -H "X-API-Key: YOUR_API_KEY" \
"https://app.scrapely.co/api/v1/scraping-sources?id=uuid-here"Response
{
"scraping_source": {
"id": "uuid-here",
"name": "Tech Founders Q1",
"status": "processing",
"leads_imported": 4200,
"total_leads": 9000,
"progress": 47,
"handles": [
{
"handle": "paulg",
"followers": {
"status": "completed",
"leads_imported": 5000,
"max_leads": 5000
},
"following": null
}
],
"created_at": "2024-01-15T10:30:00Z"
}
}pending- Job queued, not startedprocessing- Currently scrapingcompleted- Successfully finishedfailed- Error occurred
Launch Campaign
/campaignsLaunch a DM campaignLaunch a DM campaign targeting leads from your scraping sources. Supports A/B testing with multiple message variants. Maximum 25,000 leads per campaign.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Required | Campaign name |
| message | string | Required* | Message text (supports {{firstName}}) |
| message_variants | array | Optional | Message variants for A/B testing (max 5) |
| lead_source_ids | array | Required | Lead source IDs to target |
| account_ids | array | Optional | Account IDs to send from (defaults to all) |
| followups | array | Optional | Follow-up messages |
| max_leads | number | Optional | Maximum leads to target (max 25,000) |
| enable_follow | boolean | Optional | Follow the lead's profile before DM (default: false) |
| enable_like | boolean | Optional | Like the lead's recent post before DM (default: false) |
| enable_comment | boolean | Optional | Comment on the lead's post before DM (default: false) |
| comment_template | string | Optional | AI personalization template for auto-generated comments |
*Either message or message_variants is required.
Request
curl -X POST \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Outreach Campaign Q1",
"message_variants": [
{
"message": "Hey {{firstName}}, I saw your work and wanted to connect!",
"followups": [
{"wait_time": 3, "wait_unit": "days", "message": "Just bumping this up!"}
]
},
{
"message": "Hi {{firstName}}! Quick question about your business..."
}
],
"lead_source_ids": ["uuid-1", "uuid-2"],
"enable_follow": true,
"enable_like": true,
"enable_comment": true,
"comment_template": "Great insights on {{topic}}!"
}' \
https://app.scrapely.co/api/v1/campaignsResponse
{
"success": true,
"campaign_name": "Outreach Campaign Q1",
"jobs_created": 1500,
"leads_targeted": 1500,
"message_variants": 2,
"accounts_used": 2,
"distribution": [
{"account_id": "uuid", "handle": "account1", "jobs": 750},
{"account_id": "uuid", "handle": "account2", "jobs": 750}
]
}List Campaigns
/campaignsList campaigns with basic statsRequest
curl -H "X-API-Key: YOUR_API_KEY" \
"https://app.scrapely.co/api/v1/campaigns?limit=10"Response
{
"campaigns": [
{
"name": "Outreach Campaign Q1",
"total": 1500,
"completed": 1200,
"pending": 250,
"failed": 50,
"progress": 80
}
],
"pagination": {
"limit": 10,
"offset": 0,
"count": 1,
"total": 5
}
}Campaign Analytics
/campaigns/analyticsGet detailed campaign analyticsGet detailed analytics including reply rates, sentiment analysis, and per-variant A/B testing statistics. Returns the same data structure as the dashboard UI.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| campaign_name | string | Filter to specific campaign |
| account_id | string | Filter to specific account |
Request
curl -H "X-API-Key: YOUR_API_KEY" \
https://app.scrapely.co/api/v1/campaigns/analyticsResponse
{
"accounts": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"handle": "myhandle",
"name": "My Account",
"profile_image_url": "https://pbs.twimg.com/...",
"is_paused": false,
"dms_sent": 1500,
"dms_sent_24hrs": 45,
"responses": 180,
"response_rate": 12.0,
"pending_count": 250,
"sentiment": {
"positive": 120,
"negative": 15,
"neutral": 45
}
}
],
"campaigns": [
{
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"account_handle": "myhandle",
"campaign_name": "Outreach Q1",
"total": 1500,
"completed": 1200,
"pending": 250,
"failed": 50,
"remaining": 250,
"progress": 80,
"reply_count": 150,
"response_rate": 12.5
}
],
"campaignSentimentStats": [
{
"campaign_name": "Outreach Q1",
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"sentiment": {
"positive": 100,
"negative": 12,
"neutral": 38,
"total": 150
},
"reply_count": 150
}
],
"campaignVariantStats": [
{
"campaign_name": "Outreach Q1",
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"variants": [
{
"message": "Hey {{firstName}}, loved your recent post...",
"sent": 600,
"replied": 90,
"reply_rate": 15.0
},
{
"message": "Hi {{firstName}}, saw you're building...",
"sent": 600,
"replied": 60,
"reply_rate": 10.0
}
]
}
],
"totals": {
"dms_sent": 1500,
"responses": 180,
"response_rate": 12.0,
"positive": 120,
"negative": 15,
"neutral": 45
}
}Fetch Conversations
/conversationsFetch DM conversationsReturns conversations with lead info. Pass a conversation_id to get a single conversation with all messages and complete lead data.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| conversation_id | string | Optional | Get single conversation with all messages & lead info |
| account_id | string | Optional | Filter by Twitter account |
| handle | string | Optional | Filter by receiver handle |
| limit | number | Optional | Results per page (max 100) |
| cursor | string | Optional | Pagination cursor (recommended) |
| include_messages | boolean | Optional | Include full message history (for list view) |
Use cursor instead of offset for reliable pagination. The next_cursor in the response can be passed as the cursor parameter.
List Conversations
curl -H "X-API-Key: YOUR_API_KEY" \
"https://app.scrapely.co/api/v1/conversations?limit=10"List Response
{
"conversations": [
{
"conversation_id": "123456789-987654321",
"account_handle": "yourhandle",
"receiver": {
"screen_name": "prospect",
"name": "John Doe",
"bio": "Founder @ Startup",
"website": "https://example.com",
"location": "San Francisco",
"followers_count": 5000
},
"last_message": {
"text": "Thanks for reaching out!",
"time": 1709234567000,
"is_sent": false
},
"is_unread": true
}
],
"pagination": {
"limit": 10,
"count": 10,
"has_more": true
},
"next_cursor": "eyJ0IjoxNzA5MjM0NTY3MDAwLCJpIjoiYWJjMTIzIn0"
}Get Single Conversation
Pass conversation_id to get full details:
curl -H "X-API-Key: YOUR_API_KEY" \
"https://app.scrapely.co/api/v1/conversations?conversation_id=123456789-987654321"Single Conversation Response
{
"conversation": {
"id": "uuid-here",
"conversation_id": "123456789-987654321",
"account_handle": "yourhandle",
"lead": {
"user_id": "987654321",
"screen_name": "prospect",
"name": "John Doe",
"profile_image_url": "https://pbs.twimg.com/...",
"profile_banner_url": "https://pbs.twimg.com/...",
"bio": "Founder @ Startup | Building cool things",
"location": "San Francisco, CA",
"website": "https://example.com",
"followers_count": 5000,
"following_count": 1200,
"verified": false
},
"crm": {
"notes": "Interested in enterprise plan",
"deal_value": 5000.00,
"deal_currency": "USD"
},
"stats": {
"message_count": 8,
"is_unread": false,
"last_message_time": 1709234567000,
"last_message_text": "Sounds great, let's schedule a call!",
"last_message_is_sent": false
},
"messages": [
{
"text": "Hey! Saw your work on...",
"time": 1709200000000,
"sender": "123456789",
"isSent": true
},
{
"text": "Thanks for reaching out!",
"time": 1709210000000,
"sender": "987654321",
"isSent": false
}
],
"created_at": "2024-02-28T10:00:00.000Z",
"updated_at": "2024-02-28T12:30:00.000Z"
}
}Send DM
/dm/sendSend a direct messageSend a direct message to an existing conversation.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| conversation_id | string | Required | The conversation ID |
| message | string | Required | Message text (max 10,000 chars) |
| account_id | string | Required | Twitter account ID to send from |
Request
curl -X POST \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"conversation_id": "123456789-987654321",
"message": "Hey! Just following up.",
"account_id": "550e8400-e29b-41d4-a716-446655440000"
}' \
https://app.scrapely.co/api/v1/dm/sendResponse
{
"success": true,
"message_id": "1234567890123456789",
"conversation_id": "123456789-987654321",
"account_handle": "yourhandle"
}Get CRM Conversations
/crm/conversationsGet conversations organized by CRM tagsFetch conversations organized by CRM tags like "interested", "negative", "booked", etc.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| tag | string | Filter to specific tag |
| limit | number | Conversations per tag (default: 20, max: 100) |
| include_messages | boolean | Include full message history |
Request
curl -H "X-API-Key: YOUR_API_KEY" \
https://app.scrapely.co/api/v1/crm/conversationsResponse
{
"columns": {
"interested_reply": {
"conversations": [
{
"id": "conv-key",
"conversation_id": "123456-789012",
"account_handle": "myhandle",
"tag": "interested_reply",
"receiver": {
"screen_name": "lead_handle",
"name": "Interested Lead",
"bio": "CEO at...",
"followers_count": 10000
},
"crm": {
"notes": "Interested in demo",
"deal_value": 5000,
"deal_currency": "USD"
},
"last_message": {
"text": "Yes, I'd love to learn more!",
"time": "2024-01-15T14:30:00Z"
}
}
],
"count": 1
},
"negative_reply": {
"conversations": [],
"count": 0
}
},
"custom_tags": [
{"id": "uuid", "name": "Hot Lead", "color": "#ff0000", "key": "custom_uuid"}
],
"base_tags": [
"unread", "interested_reply", "negative_reply", "neutral_reply",
"engaged", "calendlyd", "booked", "not_interested", "not_qualified"
]
}Update CRM Data
/crm/updateUpdate notes, deal value, or tagsUpdate CRM data for a conversation including notes, deal value, and tags.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| conversation_id | string | Required | The conversation ID |
| account_handle | string | Required | The account handle |
| notes | string | Optional | Notes for the conversation |
| deal_value | number | Optional | Deal value |
| deal_currency | string | Optional | Currency code (default: USD) |
| tag | string | Optional | Tag to set (null to remove) |
Request
curl -X PATCH \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"conversation_id": "123456-789012",
"account_handle": "myhandle",
"notes": "Interested in enterprise plan. Follow up Monday.",
"deal_value": 10000,
"deal_currency": "USD",
"tag": "interested_reply"
}' \
https://app.scrapely.co/api/v1/crm/updateResponse
{
"success": true,
"updated": {
"conversation_id": "123456-789012",
"account_handle": "myhandle",
"notes": "Interested in enterprise plan. Follow up Monday.",
"deal_value": 10000,
"deal_currency": "USD",
"tag": "interested_reply"
}
}Schedule Tweet
/scheduled-tweetsSchedule a tweet to be posted at a specific timeSchedule a tweet to be automatically posted from one of your accounts at a specified time. The tweet will be posted by the background worker when the scheduled time arrives.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| account_id | string | Required | The account UUID to post from |
| tweet_text | string | Required | The tweet content (max 280 characters) |
| scheduled_at | string | Required | ISO 8601 timestamp for when to post (must be in the future) |
Request
curl -X POST \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"tweet_text": "Just launched a new feature! Check it out",
"scheduled_at": "2024-03-20T15:00:00Z"
}' \
https://app.scrapely.co/api/v1/scheduled-tweetsResponse
{
"success": true,
"message": "Tweet scheduled successfully",
"scheduled_tweet": {
"id": "7f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"account_handle": "myhandle",
"tweet_text": "Just launched a new feature! Check it out",
"scheduled_at": "2024-03-20T15:00:00.000Z",
"status": "pending",
"created_at": "2024-03-15T10:30:00.000Z"
}
}pending- Waiting to be postedposted- Successfully postedfailed- Failed to post (check error_message)
List Scheduled Tweets
/scheduled-tweetsList all scheduled tweetsRetrieve a list of scheduled tweets for your accounts. Filter by account, status, or use pagination.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| account_id | string | Filter by specific account UUID |
| status | string | Filter by status: pending, posted, failed |
| limit | number | Max results (default: 50, max: 100) |
| offset | number | Pagination offset |
Request
curl -H "X-API-Key: YOUR_API_KEY" \
"https://app.scrapely.co/api/v1/scheduled-tweets?status=pending&limit=10"Response
{
"scheduled_tweets": [
{
"id": "7f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c",
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"account_handle": "myhandle",
"account_name": "My Account",
"account_image": "https://pbs.twimg.com/...",
"tweet_text": "Just launched a new feature!",
"scheduled_at": "2024-03-20T15:00:00.000Z",
"status": "pending",
"posted_at": null,
"error_message": null,
"created_at": "2024-03-15T10:30:00.000Z"
}
],
"pagination": {
"limit": 10,
"offset": 0,
"count": 1,
"total": 5
}
}Cancel Scheduled Tweet
/scheduled-tweetsCancel a pending scheduled tweetCancel a scheduled tweet before it gets posted. Only tweets with status "pending" can be cancelled.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| tweet_id | string | Required | The scheduled tweet UUID to cancel |
Request
curl -X DELETE \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tweet_id": "7f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c"
}' \
https://app.scrapely.co/api/v1/scheduled-tweetsResponse
{
"success": true,
"message": "Scheduled tweet cancelled",
"tweet_id": "7f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c"
}You can only cancel tweets with status "pending". Once a tweet has been posted or failed, it cannot be cancelled.
Error Handling
The API uses conventional HTTP response codes.
HTTP Status Codes
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Invalid API key |
| 403 | Forbidden - Subscription not active |
| 429 | Rate Limited - Too many requests |
| 500 | Internal Server Error |
Error Response Format
{
"error": "Unauthorized",
"message": "Invalid API key"
}Rate Limits
API requests are rate limited to ensure fair usage.
Response Headers
Every response includes these headers:
X-Request-ID: req_m1abc123def456
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1709234567Every response includes an X-Request-ID header. Include this ID when contacting support for faster debugging.
Rate Limit Error
{
"error": "Rate limited",
"message": "Too many requests. Please try again later.",
"retry_after": 45
}- Implement exponential backoff when retrying
- Cache responses when possible
- Use webhooks for real-time updates
Webhooks
Webhooks allow you to receive real-time notifications when events occur in your Scrapely account. Configure your webhook URL in Settings to start receiving events.
Webhook Events
| Event | Description |
|---|---|
| new_reply | A prospect replied to your DM |
| account_paused | A Twitter account was disconnected or paused |
| leads_exhausted | A campaign has run out of leads to contact |
Webhook Payload Format
All webhook payloads follow this structure:
{
"event": "event_type",
"timestamp": "2024-02-28T12:00:00.000Z",
"data": {
// Event-specific data
}
}new_reply Event
Sent when a prospect replies to your DM:
{
"event": "new_reply",
"timestamp": "2024-02-28T12:00:00.000Z",
"data": {
"conversation_id": "123456789-987654321",
"account_handle": "yourhandle",
"receiver": {
"screen_name": "prospect",
"name": "John Doe",
"profile_image_url": "https://pbs.twimg.com/..."
},
"message": {
"id": "1234567890123456789",
"text": "Hey! I'm interested, let's chat.",
"created_at": "2024-02-28T12:00:00.000Z"
}
}
}account_paused Event
Sent when a Twitter account is disconnected:
{
"event": "account_paused",
"timestamp": "2024-02-28T12:00:00.000Z",
"data": {
"account_id": "550e8400-e29b-41d4-a716-446655440000",
"account_handle": "yourhandle",
"reason": "Session expired or account disconnected"
}
}leads_exhausted Event
Sent when a campaign runs out of leads:
{
"event": "leads_exhausted",
"timestamp": "2024-02-28T12:00:00.000Z",
"data": {
"campaign_id": "camp_abc123",
"campaign_name": "SaaS Founders Outreach",
"account_handle": "yourhandle",
"total_sent": 500
}
}Responding to Webhooks
Your endpoint should return a 200 status code within 30 seconds. If we don't receive a successful response, we'll retry up to 3 times with exponential backoff.
Validate the payload structure before processing to ensure it came from Scrapely.