DropReply API Reference Programmatically publish replies, upvotes, and likes on Reddit and Twitter/X through managed social media accounts.
Queue a reply to any Reddit post or tweet for async publishing.
View your plan, credit balance, and billing period at a glance.
Get notified when replies are published, fail, or get removed.
Official Node.js SDK and community libraries to get started fast.
Authentication
All API requests require a Bearer token in the Authorization header.
Authorization: Bearer drpl_live_xxxxxxxxxxxxxxxx
Key formats
| Key Prefix | Mode | Behavior |
|---|---|---|
| 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": "error_code",
"message": "Human-readable explanation."
}
Common error codes
| HTTP Status | Error Code | Meaning |
|---|---|---|
| 400 | validation_error | Missing or invalid field in the request body |
| 401 | unauthorized | Missing, empty, or invalid API key |
| 402 | insufficient_credits | Not enough credits to perform the action |
| 403 | forbidden | Workspace is suspended |
| 403 | plan_required | Feature requires a higher plan (e.g. scheduled replies) |
| 404 | not_found | Resource does not exist or does not belong to you |
| 422 | moderation_rejected | Content blocked by moderation |
| 429 | rate_limit_exceeded | Too many requests -- slow down |
| 429 | concurrent_limit | Too many replies in progress -- wait for some to finish |
| 500 | internal_error | Server error -- retry later |
Submit a reply for publishing on Reddit or Twitter/X. The reply is queued and published asynchronously by a managed account.
Request body
| Field | Type | Default | Description | |
|---|---|---|---|---|
platform | string | Required | -- | reddit or twitter |
target_url | string | Required | -- | Full URL of the post or tweet to reply to |
content | string | Required | -- | Reply text (10--2,000 characters, no URLs) |
schedule_at | string | Optional | -- | 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, orold.reddit.comURL - Twitter: must be a
twitter.com,x.com,www.twitter.com, orwww.x.comURL
Response 201 Created
{
"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
| Status | Condition |
|---|---|
| 400 | Missing or invalid field (platform, target_url, content, schedule_at) |
| 401 | Missing or invalid API key |
| 402 | Not enough credits |
| 403 | plan_required -- schedule_at requires Growth or Scale plan |
| 422 | Content blocked by moderation |
| 429 | Rate 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
Retrieve the current status and details of a specific reply.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Reply ID (e.g. rpl_a1b2c3d4e5f6g7h8) |
Response 200 OK
{
"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
| Field | Type | Description |
|---|---|---|
id | string | Unique reply ID |
platform | string | reddit or twitter |
target_url | string | The original post/tweet URL |
content | string | The reply text |
credit_cost | number | Credits charged for this reply |
status | string | Current status (see below) |
error_message | string/null | Error details if status is failed |
published_url | string/null | Public URL of the published reply |
schedule_at | string/null | Scheduled publish time (ISO 8601), or null if immediate |
published_at | string/null | ISO 8601 timestamp of when the reply was published |
created_at | string | ISO 8601 timestamp of when the reply was submitted |
Possible statuses
| Status | Description |
|---|---|
| queued | Reply is in the queue, waiting to be published |
| scheduled | Reply is scheduled for future publishing (see schedule_at) |
| publishing | A worker has picked it up and is publishing now |
| published | Successfully published -- published_url will be set |
| failed | Publishing failed -- check error_message for details |
| rejected | Blocked by content moderation |
Error responses
| Status | Condition |
|---|---|
| 401 | Missing or invalid API key |
| 404 | Reply 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/...
List replies with optional filtering and pagination. Results are ordered by created_at descending (newest first).
Query parameters
| Parameter | Type | Default | Description | |
|---|---|---|---|---|
platform | string | Optional | -- | Filter by platform: reddit or twitter |
status | string | Optional | -- | Filter by status: queued, scheduled, publishing, published, failed, rejected |
limit | number | Optional | 20 | Results per page (max 100) |
offset | number | Optional | 0 | Pagination offset |
Response 200 OK
{
"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
}
}
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']}")
Submit an upvote (Reddit) or like (Twitter/X) job. The action is queued and executed asynchronously.
Request body
| Field | Type | Description | |
|---|---|---|---|
platform | string | Required | reddit or twitter |
target_url | string | Required | Full URL of the post, comment, or tweet to upvote/like |
Response 201 Created
{
"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
| Status | Condition |
|---|---|
| 400 | Missing or invalid platform / target_url |
| 401 | Missing or invalid API key |
| 402 | Not enough credits |
| 429 | Rate 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 your current plan info, credit balance, and billing period.
Response 200 OK
{
"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
| Field | Type | Description |
|---|---|---|
plan | string | Current plan name (free, starter, growth, scale) |
credits_included | number | Monthly credits included in the plan |
credits_used | number | Credits consumed this billing period |
credits_remaining | number | Remaining included credits |
extra_credits | number | Purchased extra credits (carry over between periods) |
total_available | number | Total credits you can spend right now |
billing_period_start | string | Start of current billing period (ISO 8601) |
billing_period_end | string | End 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']}")
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
| Parameter | Type | Description | |
|---|---|---|---|
platform | string | Optional | Filter by platform: reddit or twitter |
Response 200 OK
{
"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:
| Header | Description |
|---|---|
RateLimit-Limit | Maximum requests allowed in the current window |
RateLimit-Remaining | Requests remaining in the current window |
RateLimit-Reset | Seconds until the rate limit window resets |
When you hit the limit, you receive a 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
| Constraint | Value |
|---|---|
| Minimum | 10 characters |
| Maximum | 2,000 characters |
Rejection example
{
"error": "moderation_rejected",
"message": "Contains URL"
}
Credits & Billing
Each action costs credits:
| Action | Credits |
|---|---|
| Reply (any platform) | 1 |
| Upvote / Like | 0.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_creditserror.
Refund policy
- Moderation rejected -- full credit refund (charge never deducted).
- Reply removed within 24 hours -- 50% credit refund (added to extra credits).
Plans
| Plan | Price | Replies / month | Concurrent replies | Scheduled replies | Auto-retry |
|---|---|---|---|---|---|
| Free | $0 | 3 | 1 | No | No |
| Starter | $49/mo | 25 | 3 | No | No |
| Growth | $149/mo | 100 | 10 | Yes | Yes |
| Scale | $499/mo | 500 | Unlimited | Yes | Yes |
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
| Event | When it fires |
|---|---|
reply.published | Reply was successfully published |
reply.failed | Reply failed to publish after all retries |
reply.removed | Published reply was detected as removed |
Payload format
{
"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
}
}
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
| Language | Package | Install |
|---|---|---|
| Node.js | @dropreply/sdk | npm install @dropreply/sdk |
| Python | dropreply | pip install dropreply |
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.