DropReply API Reference Programmatically publish replies, upvotes, and likes on Reddit and Twitter/X through managed social media accounts.

Base URL https://api.dropreply.com

Authentication

All API requests require a Bearer token in the Authorization header.

Header
Authorization: Bearer drpl_live_xxxxxxxxxxxxxxxx

Key formats

Key PrefixModeBehavior
drpl_live_ Live Publishes replies to real social media accounts
drpl_test_ Test Validates everything but does not actually publish

Test mode is useful during development. Requests are validated, credits are checked, and content is moderated, but nothing gets posted. Test and live keys are separate -- each workspace has one of each.

Find your API keys in the DropReply dashboard.

Error format

All errors follow a consistent structure:

Error Response
{
  "error": "error_code",
  "message": "Human-readable explanation."
}

Common error codes

HTTP StatusError CodeMeaning
400validation_errorMissing or invalid field in the request body
401unauthorizedMissing, empty, or invalid API key
402insufficient_creditsNot enough credits to perform the action
403forbiddenWorkspace is suspended
403plan_requiredFeature requires a higher plan (e.g. scheduled replies)
404not_foundResource does not exist or does not belong to you
422moderation_rejectedContent blocked by moderation
429rate_limit_exceededToo many requests -- slow down
429concurrent_limitToo many replies in progress -- wait for some to finish
500internal_errorServer error -- retry later

POST /v1/reply

Submit a reply for publishing on Reddit or Twitter/X. The reply is queued and published asynchronously by a managed account.

Request body

FieldTypeDefaultDescription
platformstringRequired--reddit or twitter
target_urlstringRequired--Full URL of the post or tweet to reply to
contentstringRequired--Reply text (10--2,000 characters, no URLs)
schedule_atstringOptional--ISO 8601 datetime to publish the reply (Growth/Scale only, up to 30 days ahead)

URL requirements

  • Reddit: must be a reddit.com, www.reddit.com, or old.reddit.com URL
  • Twitter: must be a twitter.com, x.com, www.twitter.com, or www.x.com URL

Response 201 Created

Response
{
  "id": "rpl_a1b2c3d4e5f6g7h8",
  "status": "queued",
  "platform": "reddit",
  "target_url": "https://www.reddit.com/r/saas/comments/abc123/my_post/",
  "credit_cost": 1,
  "schedule_at": null,
  "created_at": "2026-03-22T10:30:00.000Z"
}

Error responses

StatusCondition
400Missing or invalid field (platform, target_url, content, schedule_at)
401Missing or invalid API key
402Not enough credits
403plan_required -- schedule_at requires Growth or Scale plan
422Content blocked by moderation
429Rate limit exceeded, or concurrent_limit -- too many replies in progress

Examples

curl -X POST https://api.dropreply.com/v1/reply \
  -H "Authorization: Bearer drpl_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "reddit",
    "target_url": "https://www.reddit.com/r/saas/comments/abc123/looking_for_tools/",
    "content": "I have been using something similar for the past few months and it has been a game changer for productivity."
  }'
const DropReply = require('@dropreply/sdk');
const client = new DropReply('drpl_live_xxxxxxxx');

const reply = await client.reply({
  platform: 'reddit',
  target_url: 'https://www.reddit.com/r/saas/comments/abc123/looking_for_tools/',
  content: 'I have been using something similar for the past few months and it has been a game changer for productivity.'
});

console.log(reply.id);     // rpl_a1b2c3d4e5f6g7h8
console.log(reply.status); // queued
import requests

response = requests.post(
    "https://api.dropreply.com/v1/reply",
    headers={
        "Authorization": "Bearer drpl_live_xxxxxxxx",
        "Content-Type": "application/json"
    },
    json={
        "platform": "reddit",
        "target_url": "https://www.reddit.com/r/saas/comments/abc123/looking_for_tools/",
        "content": "I have been using something similar for the past few months and it has been a game changer for productivity."
    }
)

reply = response.json()
print(reply["id"])     # rpl_a1b2c3d4e5f6g7h8
print(reply["status"]) # queued

GET /v1/reply/:id

Retrieve the current status and details of a specific reply.

Path parameters

ParameterTypeDescription
idstringReply ID (e.g. rpl_a1b2c3d4e5f6g7h8)

Response 200 OK

Response
{
  "id": "rpl_a1b2c3d4e5f6g7h8",
  "platform": "reddit",
  "target_url": "https://www.reddit.com/r/saas/comments/abc123/looking_for_tools/",
  "content": "I have been using something similar for the past few months...",
  "credit_cost": 1,
  "status": "published",
  "error_message": null,
  "published_url": "https://www.reddit.com/r/saas/comments/abc123/comment/xyz789/",
  "schedule_at": null,
  "published_at": "2026-03-22T10:31:15.000Z",
  "created_at": "2026-03-22T10:30:00.000Z"
}

Response fields

FieldTypeDescription
idstringUnique reply ID
platformstringreddit or twitter
target_urlstringThe original post/tweet URL
contentstringThe reply text
credit_costnumberCredits charged for this reply
statusstringCurrent status (see below)
error_messagestring/nullError details if status is failed
published_urlstring/nullPublic URL of the published reply
schedule_atstring/nullScheduled publish time (ISO 8601), or null if immediate
published_atstring/nullISO 8601 timestamp of when the reply was published
created_atstringISO 8601 timestamp of when the reply was submitted

Possible statuses

StatusDescription
queuedReply is in the queue, waiting to be published
scheduledReply is scheduled for future publishing (see schedule_at)
publishingA worker has picked it up and is publishing now
publishedSuccessfully published -- published_url will be set
failedPublishing failed -- check error_message for details
rejectedBlocked by content moderation

Error responses

StatusCondition
401Missing or invalid API key
404Reply not found (or belongs to a different workspace)

Examples

curl https://api.dropreply.com/v1/reply/rpl_a1b2c3d4e5f6g7h8 \
  -H "Authorization: Bearer drpl_live_xxxxxxxx"
const reply = await client.getReply('rpl_a1b2c3d4e5f6g7h8');

console.log(reply.status);        // published
console.log(reply.published_url); // https://www.reddit.com/r/...
response = requests.get(
    "https://api.dropreply.com/v1/reply/rpl_a1b2c3d4e5f6g7h8",
    headers={"Authorization": "Bearer drpl_live_xxxxxxxx"}
)

reply = response.json()
print(reply["status"])        # published
print(reply["published_url"]) # https://www.reddit.com/r/...

GET /v1/replies

List replies with optional filtering and pagination. Results are ordered by created_at descending (newest first).

Query parameters

ParameterTypeDefaultDescription
platformstringOptional--Filter by platform: reddit or twitter
statusstringOptional--Filter by status: queued, scheduled, publishing, published, failed, rejected
limitnumberOptional20Results per page (max 100)
offsetnumberOptional0Pagination offset

Response 200 OK

Response
{
  "data": [
    {
      "id": "rpl_a1b2c3d4e5f6g7h8",
      "platform": "reddit",
      "target_url": "https://www.reddit.com/r/saas/comments/abc123/...",
      "content": "I have been using something similar...",
      "credit_cost": 1,
      "status": "published",
      "error_message": null,
      "published_url": "https://www.reddit.com/r/saas/comments/abc123/comment/xyz789/",
      "published_at": "2026-03-22T10:31:15.000Z",
      "created_at": "2026-03-22T10:30:00.000Z"
    }
  ],
  "pagination": {
    "total": 42,
    "limit": 20,
    "offset": 0
  }
}
Pagination: Use offset and limit to page through results. The total field tells you how many replies match your filters.

Examples

# Get published Reddit replies, page 2
curl "https://api.dropreply.com/v1/replies?platform=reddit&status=published&limit=10&offset=10" \
  -H "Authorization: Bearer drpl_live_xxxxxxxx"
const result = await client.listReplies({
  platform: 'reddit',
  status: 'published',
  limit: 10,
  offset: 0
});

console.log(result.pagination.total); // 42
result.data.forEach(r => {
  console.log(`${r.id}: ${r.status}`);
});
response = requests.get(
    "https://api.dropreply.com/v1/replies",
    headers={"Authorization": "Bearer drpl_live_xxxxxxxx"},
    params={"platform": "reddit", "status": "published", "limit": 10}
)

result = response.json()
for reply in result["data"]:
    print(f"{reply['id']}: {reply['status']}")
print(f"Total: {result['pagination']['total']}")

POST /v1/upvote

Submit an upvote (Reddit) or like (Twitter/X) job. The action is queued and executed asynchronously.

Request body

FieldTypeDescription
platformstringRequiredreddit or twitter
target_urlstringRequiredFull URL of the post, comment, or tweet to upvote/like
Credit cost: 0.25 credits per upvote/like.

Response 201 Created

Response
{
  "id": "upv_x9y8z7w6v5u4t3s2",
  "status": "queued",
  "platform": "reddit",
  "target_url": "https://www.reddit.com/r/saas/comments/abc123/comment/xyz789/",
  "credit_cost": 0.25,
  "created_at": "2026-03-22T10:35:00.000Z"
}

Error responses

StatusCondition
400Missing or invalid platform / target_url
401Missing or invalid API key
402Not enough credits
429Rate limit exceeded

Examples

curl -X POST https://api.dropreply.com/v1/upvote \
  -H "Authorization: Bearer drpl_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "reddit",
    "target_url": "https://www.reddit.com/r/saas/comments/abc123/comment/xyz789/"
  }'
const upvote = await client.upvote({
  platform: 'reddit',
  target_url: 'https://www.reddit.com/r/saas/comments/abc123/comment/xyz789/'
});

console.log(upvote.id);     // upv_x9y8z7w6v5u4t3s2
console.log(upvote.status); // queued
response = requests.post(
    "https://api.dropreply.com/v1/upvote",
    headers={
        "Authorization": "Bearer drpl_live_xxxxxxxx",
        "Content-Type": "application/json"
    },
    json={
        "platform": "reddit",
        "target_url": "https://www.reddit.com/r/saas/comments/abc123/comment/xyz789/"
    }
)

upvote = response.json()
print(upvote["id"])     # upv_x9y8z7w6v5u4t3s2
print(upvote["status"]) # queued

GET /v1/usage

Get your current plan info, credit balance, and billing period.

Response 200 OK

Response
{
  "plan": "growth",
  "credits_included": 100,
  "credits_used": 23.5,
  "credits_remaining": 76.5,
  "extra_credits": 50,
  "total_available": 126.5,
  "billing_period_start": "2026-03-01T00:00:00.000Z",
  "billing_period_end": "2026-04-01T00:00:00.000Z"
}

Response fields

FieldTypeDescription
planstringCurrent plan name (free, starter, growth, scale)
credits_includednumberMonthly credits included in the plan
credits_usednumberCredits consumed this billing period
credits_remainingnumberRemaining included credits
extra_creditsnumberPurchased extra credits (carry over between periods)
total_availablenumberTotal credits you can spend right now
billing_period_startstringStart of current billing period (ISO 8601)
billing_period_endstringEnd of current billing period (ISO 8601)

Examples

curl https://api.dropreply.com/v1/usage \
  -H "Authorization: Bearer drpl_live_xxxxxxxx"
const usage = await client.usage();

console.log(`Plan: ${usage.plan}`);
console.log(`Credits available: ${usage.total_available}`);
console.log(`Period ends: ${usage.billing_period_end}`);
response = requests.get(
    "https://api.dropreply.com/v1/usage",
    headers={"Authorization": "Bearer drpl_live_xxxxxxxx"}
)

usage = response.json()
print(f"Plan: {usage['plan']}")
print(f"Credits available: {usage['total_available']}")

GET /v1/accounts/availability

Check how many managed accounts are currently available, broken down by platform. Useful for knowing whether accounts are available before submitting a reply.

Query parameters

ParameterTypeDescription
platformstringOptionalFilter by platform: reddit or twitter

Response 200 OK

Response
{
  "accounts": [
    { "platform": "reddit",  "available": 12 },
    { "platform": "twitter", "available": 8 }
  ]
}

Examples

# All accounts
curl https://api.dropreply.com/v1/accounts/availability \
  -H "Authorization: Bearer drpl_live_xxxxxxxx"

# Only Reddit
curl "https://api.dropreply.com/v1/accounts/availability?platform=reddit" \
  -H "Authorization: Bearer drpl_live_xxxxxxxx"
const availability = await client.accountsAvailability({
  platform: 'reddit'
});

availability.accounts.forEach(a => {
  console.log(`${a.platform}: ${a.available} available`);
});
response = requests.get(
    "https://api.dropreply.com/v1/accounts/availability",
    headers={"Authorization": "Bearer drpl_live_xxxxxxxx"},
    params={"platform": "reddit"}
)

for account in response.json()["accounts"]:
    print(f"{account['platform']}: {account['available']} available")

Rate Limiting

Rate limits are enforced per workspace on a 1-minute sliding window. The default limit is 60 requests per minute; higher-tier plans may have increased limits.

Every response includes standard rate-limit headers:

HeaderDescription
RateLimit-LimitMaximum requests allowed in the current window
RateLimit-RemainingRequests remaining in the current window
RateLimit-ResetSeconds until the rate limit window resets

When you hit the limit, you receive a 429 response:

429 Response
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Please slow down."
}

Content Moderation

All reply content is checked before publishing. The following will be rejected with HTTP 422:

  • URLs -- any http://, https://, or bare domain (e.g. example.com)
  • Email addresses -- anything matching user@domain.tld
  • Phone numbers -- US-style phone numbers (with or without country code)
  • Cryptocurrency addresses -- Bitcoin, Ethereum, Litecoin, Tron wallet addresses
  • Spam / promotional content -- detected by AI moderation

Character limits

ConstraintValue
Minimum10 characters
Maximum2,000 characters

Rejection example

422 Response
{
  "error": "moderation_rejected",
  "message": "Contains URL"
}

Credits & Billing

Each action costs credits:

ActionCredits
Reply (any platform)1
Upvote / Like0.25

How credits work

  • Each plan includes a monthly credit allowance (see table below).
  • Included credits reset at the start of each billing period.
  • When included credits run out, extra credits (purchased separately) are consumed.
  • If both are exhausted, you receive a 402 insufficient_credits error.

Refund policy

  • Moderation rejected -- full credit refund (charge never deducted).
  • Reply removed within 24 hours -- 50% credit refund (added to extra credits).

Plans

PlanPriceReplies / monthConcurrent repliesScheduled repliesAuto-retry
Free$031NoNo
Starter$49/mo253NoNo
Growth$149/mo10010YesYes
Scale$499/mo500UnlimitedYesYes

Concurrent reply limits

Each plan limits how many replies can be in queued or publishing state at the same time. If you exceed the limit, you receive a 429 response with error code concurrent_limit.

Auto-retry guarantee

On Growth and Scale plans, if a published reply is detected as removed within 24 hours, it is automatically re-published on a different managed account at no extra credit cost.


Webhooks

DropReply can send webhook notifications when the status of a reply changes. Configure your webhook URL in the DropReply dashboard.

Events

EventWhen it fires
reply.publishedReply was successfully published
reply.failedReply failed to publish after all retries
reply.removedPublished reply was detected as removed

Payload format

Webhook Payload
{
  "event": "reply.published",
  "timestamp": "2026-03-22T10:31:15.000Z",
  "data": {
    "id": "rpl_a1b2c3d4e5f6g7h8",
    "platform": "reddit",
    "target_url": "https://www.reddit.com/r/saas/comments/abc123/...",
    "status": "published",
    "published_url": "https://www.reddit.com/r/saas/comments/abc123/comment/xyz789/",
    "published_at": "2026-03-22T10:31:15.000Z",
    "credit_cost": 1
  }
}
Headers: Webhook requests include an X-DropReply-Event header with the event name (e.g. reply.published). Use this to quickly route events without parsing the payload body.

SDKs & Tools

Official SDKs

LanguagePackageInstall
Node.js @dropreply/sdk npm install @dropreply/sdk
Python dropreply pip install dropreply
Quick Start
const DropReply = require('@dropreply/sdk');
const client = new DropReply('drpl_live_xxxxxxxx');

// Submit a reply
const reply = await client.reply({
  platform: 'reddit',
  target_url: 'https://www.reddit.com/r/saas/comments/abc123/...',
  content: 'Great question! Here is what worked for me...'
});

// Check status
const status = await client.getReply(reply.id);

// List all replies
const all = await client.listReplies({ status: 'published' });

// Check usage
const usage = await client.usage();

For other languages, use the REST API directly with the HTTP client of your choice. See the code examples throughout this documentation for patterns in cURL, Node.js, and Python.