Scrapely API is now live check it out here

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

text
https://app.scrapely.co/api/v1

Available Endpoints

Accounts
GET/accountsList your Twitter accounts
POST/accountsAdd a new account
DELETE/accountsRemove an account
PUT/accounts/cookiesUpdate account cookies
PUT/accounts/proxyUpdate account proxy
PATCH/accounts/pauseToggle account pause status
PATCH/accounts/pause-followupsToggle follow-ups pause status
Cookie Extraction (Deprecated)
POST/get-cookiesQueue cookie extraction job (Deprecated)
GET/get-cookies/statusCheck extraction status (Deprecated)
Lead Scraping
POST/scraping-sourcesCreate a scraping source
GET/scraping-sourcesList/check scraping status
Campaigns
POST/campaignsLaunch a DM campaign
GET/campaignsList campaigns
GET/campaigns/analyticsGet campaign analytics
Conversations
GET/conversationsFetch conversations
POST/dm/sendSend a direct message
CRM
GET/crm/conversationsGet CRM conversations by tag
PATCH/crm/updateUpdate CRM data
Scheduled Tweets
POST/scheduled-tweetsSchedule a tweet
GET/scheduled-tweetsList scheduled tweets
DELETE/scheduled-tweetsCancel scheduled tweet

Quick Start

1. Generate an API key from your Settings page

2. Make your first API call:

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  https://app.scrapely.co/api/v1/accounts

OpenAPI Specification

Download our OpenAPI spec to generate typed clients for any language:

bash
# 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.yaml

Authentication

All API requests require authentication using an API key. Generate API keys from your Settings page.

X-API-Key Header (Recommended)

bash
curl -H "X-API-Key: sk_live_your_api_key" \
  https://app.scrapely.co/api/v1/accounts

Authorization Bearer Header

bash
curl -H "Authorization: Bearer sk_live_your_api_key" \
  https://app.scrapely.co/api/v1/accounts
Keep your API key secret!

Never expose your API key in client-side code or public repositories.


List Accounts

GET/accountsList your connected Twitter accounts

Returns a list of all active Twitter accounts. Use the account id when sending DMs.

Request

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  https://app.scrapely.co/api/v1/accounts

Response

json
{
  "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

FieldTypeDescription
is_pausedbooleanWhether DM sending is paused for this account
followups_pausedbooleanWhether follow-up messages are paused
warmup_pausedbooleanWhether account warmup is paused
ai_setter_enabledbooleanWhether AI setter is enabled for this account

Add Account

POST/accountsAdd a new Twitter account

Add a new Twitter account to your workspace. Requires cookies exported from your browser and a proxy configuration.

Request Body

ParameterTypeRequiredDescription
handlestringRequiredTwitter handle (with or without @)
cookiesarrayRequiredArray of cookie objects (Chrome export format)
proxystringRequiredProxy URL (e.g., http://proxy.example.com:8080)
proxy_authstringRequiredProxy authentication (username:password)
xchat_pinstringRequiredX chat PIN code

Request

bash
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/accounts

Response

json
{
  "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
  }
}
Cookie Requirements

Cookies must include at minimum ct0 and auth_token. Use a browser extension like "EditThisCookie" to export cookies from Twitter.


Remove Account

DELETE/accountsRemove a Twitter account

Remove a Twitter account from your workspace. You can identify the account by either its UUID or Twitter handle.

Request Body

ParameterTypeRequiredDescription
account_idstringRequired*The account UUID to remove
handlestringRequired*Twitter handle to remove (with or without @)

*Either account_id or handle is required.

Request (by ID)

bash
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/accounts

Request (by Handle)

bash
curl -X DELETE \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "handle": "myhandle"
  }' \
  https://app.scrapely.co/api/v1/accounts

Response

json
{
  "success": true,
  "message": "Account removed successfully",
  "account": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "handle": "myhandle"
  }
}
Warning: This action is permanent

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.


Update Cookies

PUT/accounts/cookiesUpdate cookies for an existing account

Update cookies for an existing account when the session expires. This will also reactivate the account if it was disabled.

Request Body

ParameterTypeRequiredDescription
account_idstringRequiredThe account UUID
cookiesarrayRequiredArray of cookie objects

Request

bash
curl -X PUT \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "550e8400-e29b-41d4-a716-446655440000",
    "cookies": [
      {"name": "ct0", "value": "new_value...", "domain": ".twitter.com"},
      {"name": "auth_token", "value": "new_token...", "domain": ".twitter.com"}
    ]
  }' \
  https://app.scrapely.co/api/v1/accounts/cookies

Response

json
{
  "success": true,
  "message": "Cookies updated successfully",
  "account": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "handle": "myhandle",
    "is_active": true
  }
}

Update Proxy

PUT/accounts/proxyUpdate proxy settings for an existing account

Update the proxy configuration for an existing Twitter account. Each account uses its own proxy to avoid detection.

Request Body

ParameterTypeRequiredDescription
account_idstringRequiredThe account UUID
proxystringRequiredProxy URL (e.g., "161.77.187.46:12323")
proxy_authstringRequiredProxy authentication (username:password)

Request

bash
curl -X PUT \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "550e8400-e29b-41d4-a716-446655440000",
    "proxy": "161.77.187.46:12323",
    "proxy_auth": "username:password"
  }' \
  https://app.scrapely.co/api/v1/accounts/proxy

Response

json
{
  "success": true,
  "message": "Proxy updated successfully",
  "account": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "handle": "myhandle",
    "proxy": "161.77.187.46:12323",
    "proxy_auth": "username:password"
  }
}

Toggle Pause Status

PATCH/accounts/pausePause or unpause DM sending for an account

Pause or unpause DM sending for a specific Twitter account. When paused, the account will not send any DMs until unpaused.

Request Body

ParameterTypeRequiredDescription
account_idstringRequiredThe account UUID
is_pausedbooleanRequiredSet to true to pause, false to unpause

Request

bash
curl -X PATCH \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "550e8400-e29b-41d4-a716-446655440000",
    "is_paused": true
  }' \
  https://app.scrapely.co/api/v1/accounts/pause

Response

json
{
  "success": true,
  "message": "Account paused",
  "account": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "handle": "myhandle",
    "is_paused": true
  }
}

Toggle Follow-ups Pause Status

PATCH/accounts/pause-followupsPause or unpause follow-up messages for an account

Pause or unpause follow-up messages for a specific Twitter account. When paused, the account will not send any follow-up messages until unpaused.

Request Body

ParameterTypeRequiredDescription
account_idstringRequiredThe account UUID
followups_pausedbooleanRequiredSet to true to pause, false to unpause

Request

bash
curl -X PATCH \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "550e8400-e29b-41d4-a716-446655440000",
    "followups_paused": true
  }' \
  https://app.scrapely.co/api/v1/accounts/pause-followups

Response

json
{
  "success": true,
  "message": "Follow-ups paused",
  "account": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "handle": "myhandle",
    "followups_paused": true
  }
}

Extract Cookies (Deprecated)

POST/get-cookiesQueue a cookie extraction job
Endpoint Deprecated

This endpoint is temporarily unavailable. Cookie extraction functionality is being redesigned. Please check back later or contact support for updates.

Previously: Submit account credentials and receive the session cookies for a Twitter account. Jobs are processed sequentially. Processing typically takes 1-2 minutes.


Check Extraction Status (Deprecated)

GET/get-cookies/statusCheck cookie extraction job status
Endpoint Deprecated

This endpoint is temporarily unavailable. Cookie extraction functionality is being redesigned. Please check back later or contact support for updates.

Previously: Poll this endpoint to check the status of a cookie extraction job and retrieve the results when completed.


Create Scraping Source

POST/scraping-sourcesCreate a new lead source by scraping Twitter

Create a lead source by scraping followers and/or following from Twitter accounts. Credits are consumed based on the number of leads scraped.

Request Body

ParameterTypeRequiredDescription
namestringRequiredName for the lead source
sourcesarrayRequiredArray of scraping targets
filtersobjectOptionalFilter configuration to filter scraped leads

Source Object

ParameterTypeDescription
handlestringTwitter handle to scrape
followersbooleanScrape followers
followingbooleanScrape 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.

ParameterTypeDescription
includeKeywordsarrayArray of keyword groups. Each group is an array of keywords. Leads must match keywords in their bio/description.
excludeKeywordsarrayArray of keyword groups to exclude. Leads matching these keywords will be filtered out.
includeWithinLogicstring"AND" or "OR". Logic within each include keyword group. Default: "AND"
includeBetweenLogicstring"AND" or "OR". Logic between include keyword groups. Default: "OR"
excludeWithinLogicstring"AND" or "OR". Logic within each exclude keyword group. Default: "AND"
excludeBetweenLogicstring"AND" or "OR". Logic between exclude keyword groups. Default: "OR"
locationExcludeKeywordsarrayArray of location keywords to exclude (e.g., country names).
followersobject{ min: number, max: number }. Only keep leads who have this many followers themselves.
followingobject{ min: number, max: number }. Only keep leads who are following this many accounts.
hasWebsitebooleantrue = only leads with website, false = only leads without website, null = no filter.

Request

bash
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-sources

Response

json
{
  "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

GET/scraping-sourcesList scraping sources or get status

Check the status of your scraping jobs. Pass an id parameter to get detailed status for a specific source.

Query Parameters

ParameterTypeDescription
idstringGet specific source by ID
limitnumberResults per page (default: 20, max: 100)
offsetnumberPagination offset

Request

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://app.scrapely.co/api/v1/scraping-sources?id=uuid-here"

Response

json
{
  "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"
  }
}
Status Values
  • pending - Job queued, not started
  • processing - Currently scraping
  • completed - Successfully finished
  • failed - Error occurred

Launch Campaign

POST/campaignsLaunch a DM campaign

Launch 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

ParameterTypeRequiredDescription
namestringRequiredCampaign name
messagestringRequired*Message text (supports {{firstName}})
message_variantsarrayOptionalMessage variants for A/B testing (max 5)
lead_source_idsarrayRequiredLead source IDs to target
account_idsarrayOptionalAccount IDs to send from (defaults to all)
followupsarrayOptionalFollow-up messages
max_leadsnumberOptionalMaximum leads to target (max 25,000)
enable_followbooleanOptionalFollow the lead's profile before DM (default: false)
enable_likebooleanOptionalLike the lead's recent post before DM (default: false)
enable_commentbooleanOptionalComment on the lead's post before DM (default: false)
comment_templatestringOptionalAI personalization template for auto-generated comments

*Either message or message_variants is required.

Request

bash
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/campaigns

Response

json
{
  "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

GET/campaignsList campaigns with basic stats

Request

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://app.scrapely.co/api/v1/campaigns?limit=10"

Response

json
{
  "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

GET/campaigns/analyticsGet detailed campaign analytics

Get detailed analytics including reply rates, sentiment analysis, daily (24-hour) reply and positive reply counts, and per-variant A/B testing statistics. Returns the same data structure as the dashboard UI.

Query Parameters

ParameterTypeDescription
campaign_namestringFilter to specific campaign
account_idstringFilter to specific account

Request

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  https://app.scrapely.co/api/v1/campaigns/analytics

Response

json
{
  "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,
      "replies_24hrs": 12,
      "positive_replies_24hrs": 8,
      "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,
    "dms_sent_24hrs": 45,
    "replies_24hrs": 12,
    "positive_replies_24hrs": 8,
    "responses": 180,
    "response_rate": 12.0,
    "positive": 120,
    "negative": 15,
    "neutral": 45
  }
}

Fetch Conversations

GET/conversationsFetch DM conversations

Returns conversations with lead info. Pass a conversation_id to get a single conversation with all messages and complete lead data.

Query Parameters

ParameterTypeRequiredDescription
conversation_idstringOptionalGet single conversation with all messages & lead info
account_idstringOptionalFilter by Twitter account
handlestringOptionalFilter by receiver handle
limitnumberOptionalResults per page (max 100)
cursorstringOptionalPagination cursor (recommended)
include_messagesbooleanOptionalInclude full message history (for list view)
Cursor Pagination (Recommended)

Use cursor instead of offset for reliable pagination. The next_cursor in the response can be passed as the cursor parameter.

List Conversations

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://app.scrapely.co/api/v1/conversations?limit=10"

List Response

json
{
  "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:

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://app.scrapely.co/api/v1/conversations?conversation_id=123456789-987654321"

Single Conversation Response

json
{
  "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

POST/dm/sendSend a direct message

Send a direct message to an existing conversation.

Request Body

ParameterTypeRequiredDescription
conversation_idstringRequiredThe conversation ID
messagestringRequiredMessage text (max 10,000 chars)
account_idstringRequiredTwitter account ID to send from

Request

bash
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/send

Response

json
{
  "success": true,
  "message_id": "1234567890123456789",
  "conversation_id": "123456789-987654321",
  "account_handle": "yourhandle"
}

Get CRM Conversations

GET/crm/conversationsGet conversations organized by CRM tags

Fetch conversations organized by CRM tags like "interested", "negative", "booked", etc.

Query Parameters

ParameterTypeDescription
tagstringFilter to specific tag
limitnumberConversations per tag (default: 20, max: 100)
include_messagesbooleanInclude full message history

Request

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  https://app.scrapely.co/api/v1/crm/conversations

Response

json
{
  "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

PATCH/crm/updateUpdate notes, deal value, or tags

Update CRM data for a conversation including notes, deal value, and tags.

Request Body

ParameterTypeRequiredDescription
conversation_idstringRequiredThe conversation ID
account_handlestringRequiredThe account handle
notesstringOptionalNotes for the conversation
deal_valuenumberOptionalDeal value
deal_currencystringOptionalCurrency code (default: USD)
tagstringOptionalTag to set (null to remove)

Request

bash
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/update

Response

json
{
  "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

POST/scheduled-tweetsSchedule a tweet to be posted at a specific time

Schedule 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

ParameterTypeRequiredDescription
account_idstringRequiredThe account UUID to post from
tweet_textstringRequiredThe tweet content (max 280 characters)
scheduled_atstringRequiredISO 8601 timestamp for when to post (must be in the future)

Request

bash
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-tweets

Response

json
{
  "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"
  }
}
Tweet Status
  • pending - Waiting to be posted
  • posted - Successfully posted
  • failed - Failed to post (check error_message)

List Scheduled Tweets

GET/scheduled-tweetsList all scheduled tweets

Retrieve a list of scheduled tweets for your accounts. Filter by account, status, or use pagination.

Query Parameters

ParameterTypeDescription
account_idstringFilter by specific account UUID
statusstringFilter by status: pending, posted, failed
limitnumberMax results (default: 50, max: 100)
offsetnumberPagination offset

Request

bash
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://app.scrapely.co/api/v1/scheduled-tweets?status=pending&limit=10"

Response

json
{
  "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

DELETE/scheduled-tweetsCancel a pending scheduled tweet

Cancel a scheduled tweet before it gets posted. Only tweets with status "pending" can be cancelled.

Request Body

ParameterTypeRequiredDescription
tweet_idstringRequiredThe scheduled tweet UUID to cancel

Request

bash
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-tweets

Response

json
{
  "success": true,
  "message": "Scheduled tweet cancelled",
  "tweet_id": "7f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c"
}
Note

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

CodeDescription
200Success
400Bad Request - Invalid parameters
401Unauthorized - Invalid API key
403Forbidden - Subscription not active
429Rate Limited - Too many requests
500Internal Server Error

Error Response Format

json
{
  "error": "Unauthorized",
  "message": "Invalid API key"
}

Rate Limits

API requests are rate limited to ensure fair usage.

60 requests
per minute per API key

Response Headers

Every response includes these headers:

text
X-Request-ID: req_m1abc123def456
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1709234567
Request IDs

Every response includes an X-Request-ID header. Include this ID when contacting support for faster debugging.

Rate Limit Error

json
{
  "error": "Rate limited",
  "message": "Too many requests. Please try again later.",
  "retry_after": 45
}
Best Practices
  • 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

EventDescription
new_replyA prospect replied to your DM
account_pausedA Twitter account was disconnected or paused
leads_exhausted (Deprecated)A campaign has run out of leads to contact (Temporarily unavailable)

Webhook Payload Format

All webhook payloads follow this structure:

json
{
  "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:

json
{
  "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:

json
{
  "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 (Deprecated)

Webhook Deprecated

This webhook is temporarily unavailable. The leads_exhausted webhook is being redesigned. Please check back later or contact support for updates.

Previously: Sent when a campaign runs out of leads:

json
{
  "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.

Verifying Webhooks

Validate the payload structure before processing to ensure it came from Scrapely.


MCP Server

The Scrapely MCP (Model Context Protocol) server lets AI assistants like Claude directly manage your Twitter/X DM outreach — campaigns, lead scraping, conversations, CRM, and scheduled tweets — all through natural language.

Requirements

RequirementDetails
Node.jsv18 or higher
API KeyGenerate from Settings
MCP ClientClaude Code, Claude Desktop, or any MCP-compatible client

Installation

1. Clone or download the MCP server:

bash
cd scrapely-mcp-server
npm install

2. Set your API key:

bash
export SCRAPELY_API_KEY=sk_live_your_key_here

Connect to Claude Code

Run this command to register the MCP server with Claude Code:

bash
claude mcp add scrapely -- node /path/to/scrapely-mcp-server/server.js

Connect to Claude Desktop

Add this to ~/Library/Application Support/Claude/claude_desktop_config.json:

json
{
  "mcpServers": {
    "scrapely": {
      "command": "node",
      "args": ["/path/to/scrapely-mcp-server/server.js"],
      "env": {
        "SCRAPELY_API_KEY": "sk_live_your_key_here"
      }
    }
  }
}

Test with MCP Inspector

The MCP Inspector opens a browser GUI where you can test every tool before connecting to Claude:

bash
SCRAPELY_API_KEY=sk_live_your_key npm run inspect

Available Tools

Once connected, the MCP server exposes 18 tools that map 1:1 to the Scrapely API:

ToolDescription
list_accountsList all connected Twitter/X accounts
add_accountAdd a new account (cookies + proxy)
remove_accountRemove an account by ID or handle
update_cookiesRefresh cookies for an existing account
toggle_pausePause/unpause DM sending
toggle_followups_pausePause/unpause follow-up messages
create_scraping_sourceScrape followers/following with filters
check_scraping_statusCheck progress of scraping jobs
launch_campaignLaunch a DM campaign with A/B testing
list_campaignsList campaigns with stats
get_campaign_analyticsReply rates, sentiment, A/B variant stats
fetch_conversationsFetch conversations with message history
send_dmSend a DM to an existing conversation
get_crm_dataGet conversations organized by CRM tags
update_crmUpdate notes, deal value, and tags
schedule_tweetSchedule a tweet for later
list_scheduled_tweetsList scheduled tweets with filters
cancel_scheduled_tweetCancel a pending scheduled tweet

Example Prompts

Once connected to Claude, you can use natural language:

text
"Show me all my connected accounts"

"Scrape followers of @naval and @paulg, filter for founders with 1k+ followers"

"Launch a campaign called Q1 Outreach targeting my Tech Founders source"

"What are my campaign analytics? Which variant is performing best?"

"Show me all interested replies in the CRM"

"Send a followup to conversation 123456-789012"

"Schedule a tweet from my main account for tomorrow at 9am"

"Pause DM sending on my backup account"
How it works

The MCP server translates natural language requests into Scrapely API calls. Every tool maps directly to an API endpoint documented above — same authentication, same payloads, same responses. Your API key is passed via the SCRAPELY_API_KEY environment variable.