OutReply Public API
A clean, scoped REST API for automating your social media presence. Schedule posts, upload media, moderate comments, and list your brands & pages from any language that speaks HTTP. Designed for Make.com, Zapier, n8n, custom cron jobs, and in-house apps.
Current version
This documentation covers v1. We add new fields non-breakingly and version the URL (/api/v2) before any breaking change.
Quickstart
- Open the API keys page in your OutReply dashboard.
- Click + New token, name it, pick only the scopes you need, then Create.
- Copy the token (starts with
outreply_live_) — it is shown only once. - Call any endpoint with
Authorization: Bearer <your token>.
# Who am I and what can this token do? curl https://api.outreply.com/api/v1/me \ -H "Authorization: Bearer outreply_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Prefer a typed client?
We publish official SDKs for Node.js and Python — see Official SDKs below. One line to install, typed resources, automatic idempotency, and a built-in webhook signature verifier.
Official SDKs
Thin, typed wrappers around the same REST endpoints documented on this page. Zero runtime dependencies on Node (uses fetch), httpx on Python. Both ship with a webhook signature verifier, typed errors, and automatic idempotency keys on write requests.
POST/DELETE gets an Idempotency-Key automatically — safe retries out of the box.Install
# Node.js npm install @outreply/node # Python pip install outreply
Node.js quickstart
import OutReply from "@outreply/node"; const client = new OutReply({ apiKey: process.env.OUTREPLY_API_KEY }); // Who am I? const me = await client.me.retrieve(); // Schedule a post const post = await client.posts.schedule({ page_id: "6601...", content: "Hello from the Node SDK 👋", scheduled_at: new Date(Date.now() + 60 * 60 * 1000).toISOString(), });
Python quickstart
from outreply import OutReply client = OutReply(api_key=os.environ["OUTREPLY_API_KEY"]) me = client.me.retrieve() post = client.posts.schedule( page_id="6601...", content="Hello from the Python SDK 👋", scheduled_at="2026-05-01T10:00:00Z", )
Webhook verification
// Node: Express receiver import { verifyWebhook } from "@outreply/node/webhooks"; app.post("/webhooks/outreply", express.raw({ type: "application/json" }), (req, res) => { const event = verifyWebhook({ rawBody: req.body, signatureHeader: req.header("x-outreply-signature"), secret: process.env.OUTREPLY_WEBHOOK_SECRET, }); // event is typed by event name res.status(200).end(); });
# Python: stdlib-friendly from outreply.webhooks import verify_webhook event = verify_webhook( raw_body=request.body, signature_header=request.headers["x-outreply-signature"], secret=os.environ["OUTREPLY_WEBHOOK_SECRET"], )
Status: 1.0 beta
Both SDKs follow semver. We version the API URL (/api/v2) before any breaking change, so 1.x will keep working against the current API indefinitely. Bug reports and PRs welcome on outreply-node or outreply-python.
Authentication
Every request to /api/v1/* (except the root probe /api/v1/) must include an API token.
Bearer header (recommended)
Authorization: Bearer outreply_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Alternative: X-API-Key header
X-API-Key: outreply_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Tokens begin with outreply_live_ (older orply_live_ tokens still work for backward compatibility). If a token leaks, revoke or rotate it immediately from the dashboard.
Scopes
Scopes gate what a token can do. Grant the minimum set your integration needs.
| Scope | Group | Grants |
|---|---|---|
read:account | Account | Basic user info + quota |
read:brands | Brands | List brands you collaborate on |
read:pages | Pages | List social pages under those brands |
read:posts | Posts | Scheduled & published posts |
write:posts | Posts | Schedule, cancel, or reschedule posts |
read:comments | Comments | List comments on published posts |
write:comments | Comments | Reply to comments |
read:media | Media | List your uploaded media |
write:media | Media | Upload & delete media |
* | — | All of the above (discouraged) |
A request without the required scope returns 403 MISSING_SCOPE. The response body lists both the required scope and your token's current scopes.
Tiers & limits
API quotas now meter the actions that actually cost us money (publishes, comment replies) separately from cheap reads. Every counter resets on the 1st of each UTC month.
| Limit | Free | Pro | Elite |
|---|---|---|---|
Publishes / month (/posts/publish + /posts/schedule) | 60 | 500 | 3 000 |
Comment replies / month (/comments/reply) | 200 | 3 000 | 20 000 |
Read requests / month (GET *) | 10 000 | 100 000 | 1 000 000 |
| Webhook deliveries / month | 2 000 | 50 000 | 500 000 |
| Requests per minute (burst) | 10 | 60 | 300 |
| Concurrent upload storage | 100 MB | 1 GB | 5 GB |
| Max file size per upload | 25 MB | 100 MB | 250 MB |
| Active keys | 10 | 10 | 25 |
| Key expiration | up to 2 years | up to 2 years | up to 2 years |
Per-page publish guardrails (platform-aware, all tiers)
Monthly quotas gate our infra; these guardrails protect your connected accounts from each platform's own spam-detection. They're tuned per platform and apply on every tier:
| Platform | Max / hour | Max / 24h |
|---|---|---|
Facebook (FB) | 10 | 40 |
Instagram (IG) | 8 | 30 |
LinkedIn (LN) | 3 | 15 |
TikTok (TT) | 10 | 50 |
X / Twitter (TW) | 50 | 300 |
- 60 s minimum gap between scheduled posts on the same page.
- 500 publishes / brand / 24h runaway safety-net (sits well above any legitimate multi-page setup).
Page caps return 429 PAGE_PUBLISH_GUARDRAIL; the brand safety-net returns 429 BRAND_PUBLISH_GUARDRAIL. Both include retry_after_seconds.
How storage works
Uploaded files count against your concurrent storage quota until the post they're
attached to publishes (then they're freed), or you delete them. Passing media_urls
in /posts/schedule does not touch your storage quota — we
download the asset only when it's time to publish.
Every response includes headers that show your real-time budget:
X-API-Tier: pro X-RateLimit-Limit: 30 X-RateLimit-Remaining: 28 X-RateLimit-Reset: 1744963280 X-API-Scopes: read:pages write:posts write:media
Security controls
media_urls validated to reject localhost, private ranges, and non-http(s) schemes.Sandbox tokens
Every new OutReply account is issued a sandbox API token automatically — no credit card, no paid plan. Sandbox tokens let you try the API before committing.
- Prefix:
outreply_test_… - Lifetime cap: 100 requests total
- Rate: 5 / minute, 50 / day
- Scopes: read-only (
read:account,read:brands,read:pages,read:posts,read:comments,read:media) - Returned once in the signup response as
sandbox_api_token, then shown in the dashboard.
When the lifetime cap is reached the API returns 402 SANDBOX_EXHAUSTED with an
upgrade_url pointing at the dashboard. Sandbox requests do not
count against your paid quota and don't trigger webhooks.
Collaborator-issued tokens
OutReply is brand-native: every integration is owned by a brand, and collaborators can issue their own API keys for brands they help manage.
- Only collaborators with Full access can create keys — this keeps scopes aligned with collaborator permissions and prevents privilege mismatches.
- A collaborator-issued key is hard-bound to one brand
(
on_behalf_of_brand_id) and stamped withissued_by_collaborator_id. - Every create / revoke / rotate is written to the brand's audit log, so owners always have a timeline of who did what.
- Automatic revoke: when a collaborator is removed from the brand,
every API key they issued is immediately revoked. Requests then fail with
401 TOKEN_REVOKED. - Permission downgrade: if a collaborator loses
full_controllater, their live keys stop working with403 COLLABORATOR_INSUFFICIENT.
Idempotency
All POST, PATCH and DELETE endpoints accept an
Idempotency-Key request header (Stripe-compatible). If your request fails
mid-flight, you can safely retry with the same key — we return the original response
instead of performing the action twice.
curl https://api.outreply.com/api/v1/posts/schedule \ -H "Authorization: Bearer outreply_live_..." \ -H "Idempotency-Key: 8f1c1d7a-2a99-4c12-9fcc-6b5d22e52a7b" \ -H "Content-Type: application/json" \ -d '{"page_id":"...","message":"Launch!","publish_at":"2026-05-01T10:00:00Z"}'
- Keys are scoped per API token and stored for 24 hours.
- Replays return the cached body with header
Idempotency-Replayed: true. - Same key + different request body →
409 IDEMPOTENCY_KEY_MISMATCH. - Binary multipart uploads are skipped automatically — use a distinct key per upload.
- Keys must be 1–120 characters. We recommend UUIDv4.
Webhooks
Subscribe a URL to events and receive signed HTTP callbacks the moment they happen — no polling required. Manage subscriptions in Dashboard → API → Webhooks.
Events
| Event | Fires when |
|---|---|
post.published | A scheduled post is successfully published on the platform. |
post.failed | All retry attempts for a scheduled post were exhausted. |
comment.received | Someone comments on one of your linked pages. |
comment.replied | A reply was posted through the API. |
account.quota.warning | Your account crossed 80% of a monthly action bucket (publishes / replies / reads / webhooks). Fires once per bucket per month. |
Payload shape
{
"event": "post.published",
"created_at": "2026-04-12T10:14:22.917Z",
"data": {
"userId": "65f...",
"brandId": "65f...",
"post": { /* scheduled post object */ }
}
}Signature verification
Every request carries X-OutReply-Signature: sha256=<hex>. Verify with HMAC-SHA256 over the raw body using your webhook secret. Or skip the boilerplate and use verifyWebhook from @outreply/node/webhooks / verify_webhook from outreply.webhooks — both handle rotation-window multi-signatures correctly.
const crypto = require("crypto"); function verify(rawBody, header, secret) { const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex"); // header may contain multiple signatures during a secret rotation window return header.split(",").some(s => s.trim() === `sha256=${expected}`); }
Retries & auto-disable
- Any non-2xx response (or timeout > 10s) is retried up to 5 times with exponential backoff: 30s → 2m → 10m → 30m → 2h.
- After 20 consecutive failures the webhook is auto-disabled — re-enable it from the dashboard once the receiver is healthy.
- Every delivery is logged for 30 days; inspect them from the dashboard or via the API.
Secret rotation
Click Rotate secret on a webhook to generate a new signing key. The previous secret stays valid for 24 hours so your receivers can deploy the new value without downtime. During that window each delivery's signature header lists both signatures separated by a comma — your verifier only needs to accept whichever matches.
Errors
All errors return JSON with an error string and a stable machine-readable code. Example:
{
"error": "This API token is missing the required scope: write:posts",
"code": "MISSING_SCOPE",
"required_scope": "write:posts",
"your_scopes": ["read:posts"]
}| HTTP | Code | Meaning |
|---|---|---|
| 400 | MISSING_FIELD | Required field missing from request body |
| 400 | INVALID_DATE | Malformed timestamp |
| 400 | INVALID_MEDIA_URL | media_urls contains localhost, private IP, or non-http(s) URL |
| 400 | INVALID_FILE_CONTENT | Uploaded file's magic bytes don't match declared MIME |
| 400 | UPLOAD_ERROR | Malformed multipart, unsupported extension, etc. |
| 401 | MISSING_TOKEN | No token in request |
| 401 | INVALID_TOKEN | Token is malformed or not found |
| 401 | TOKEN_REVOKED | Token was revoked |
| 401 | TOKEN_EXPIRED | Token past its expiry date |
| 403 | MISSING_SCOPE | Token lacks required scope |
| 403 | IP_NOT_ALLOWED | Request IP not in token's allowlist |
| 403 | BRAND_NOT_AUTHORIZED | Token can't reach the requested brand |
| 403 | COLLABORATOR_INSUFFICIENT | The issuing collaborator no longer has full access |
| 404 | NOT_FOUND | Resource does not exist or not yours |
| 409 | MEDIA_IN_USE | Media is attached to a pending post |
| 413 | FILE_TOO_LARGE | Upload exceeds per-file limit |
| 413 | QUOTA_EXCEEDED | Upload would exceed concurrent storage quota |
| 429 | RATE_LIMITED | Too many requests per minute — retry after Retry-After seconds |
| 429 | DAILY_LIMIT_EXCEEDED | Daily request budget consumed |
| 402 | SANDBOX_EXHAUSTED | Sandbox token hit its 100-request lifetime cap — see response upgrade_url |
| 400 | INVALID_IDEMPOTENCY_KEY | Idempotency-Key is missing or > 120 chars |
| 409 | IDEMPOTENCY_KEY_MISMATCH | Same Idempotency-Key used with a different request body |
| 500 | SERVER_ERROR | Something went wrong on our side |
Machine-readable catalog
The full up-to-date list of error codes — with category, HTTP status, message, and
recommended fix — is available as JSON at
GET /api/v1/errors
(no authentication required).
Endpoint reference
Returns the authenticated user, the current API key's metadata, and live quota usage.
Response 200
{
"user": { "id": "6501...", "email": "you@example.com", "firstname": "Alex", "lastname": "Doe" },
"credits": { "remaining": 420, "plan": "pro" },
"tier": "pro",
"api_key": {
"id": "6601...",
"name": "Zapier integration",
"prefix": "outreply_live_ab12c",
"scopes": ["read:account", "write:posts"],
"brand_ids": [],
"expires_at": null,
"last_used_at": "2026-04-15T14:22:08.000Z",
"request_count": 142
},
"quota": {
"storage": { "used_bytes": 2345678, "limit_bytes": 1073741824, "remaining_bytes": 1071396146, "max_file_bytes": 104857600 },
"rate_limit": { "per_minute": 60, "per_day": 90000 },
"monthly": {
"year_month": "2026-05",
"resets_at": "2026-06-01T00:00:00.000Z",
"publishes": { "used": 84, "limit": 500, "remaining": 416 },
"replies": { "used": 312, "limit": 3000, "remaining": 2688 },
"reads": { "used": 5421,"limit": 100000, "remaining": 94579 },
"webhooks": { "used": 41, "limit": 50000, "remaining": 49959 },
"writes": { "used": 17, "limit": null, "remaining": null },
"total_requests": 5875
},
"publish_guardrails": {
"perPage": {
"FB": { "perHour": 10, "per24h": 40 },
"IG": { "perHour": 8, "per24h": 30 },
"LN": { "perHour": 3, "per24h": 15 },
"TT": { "perHour": 10, "per24h": 50 },
"TW": { "perHour": 50, "per24h": 300 }
},
"minGapBetweenSchedulesMs": 60000,
"perBrandPer24hSafetyNet": 500
}
}
}Lightweight introspection. Use for health checks or "whoami" probes — any valid token works regardless of scopes.
Response 200
{
"authenticated_as": { "user_id": "...", "email": "you@example.com", "firstname": "Alex", "lastname": "Doe" },
"api_key": { "id": "...", "name": "Zapier", "prefix": "outreply_live_ab12c", "scopes": ["*"], "expires_at": null }
}Lists the brands you collaborate on. If the token was restricted to specific brands at creation time, only those are returned.
Response 200
{
"brands": [
{
"id": "65f...",
"name": "Acme Co.",
"logo": "https://.../logo.png",
"timezone": "Europe/Paris",
"created_at": "2025-01-08T10:20:30.000Z",
"pages_count": 4
}
]
}Details for a single brand, including its linked pages.
Response 200
{
"brand": {
"id": "65f...",
"name": "Acme Co.",
"logo": "https://.../logo.png",
"timezone": "Europe/Paris",
"pages": [ /* same as /pages response */ ]
}
}All pages linked to a brand. Identical shape to /pages filtered by brand.
Every social page across every brand you can reach, flattened for easy iteration.
Query parameters
| Name | Type | Description |
|---|---|---|
platform optional | string | Filter by facebook, instagram, linkedin, twitter, tiktok, youtube |
brand_id optional | string | Limit to a specific brand |
Response 200
{
"pages": [
{
"id": "6711...",
"brand_id": "65f...",
"brand_name": "Acme Co.",
"platform": "instagram",
"name": "Acme Official",
"username": "acme",
"followers": 12450,
"expired": false
}
]
}Details for a single page.
Response 200
{
"page": {
"id": "6711...",
"brand_id": "65f...",
"platform": "instagram",
"name": "Acme Official",
"username": "acme",
"followers": 12450,
"profile_picture": "https://...",
"expired": false,
"created_at": "2024-12-01T..."
}
}Schedule a post on one of your pages. Must be at least 10 minutes and at most 75 days in the future.
Body
| Field | Type | Description |
|---|---|---|
page_id required | string | Target page ID from /pages |
scheduled_at required | ISO-8601 | UTC timestamp. E.g. 2026-05-12T14:30:00Z |
message optional* | string | Post text. Max 5 000 chars. *Either message or one media item is required. |
media_ids optional | string[] | IDs of previously uploaded media (see /media/upload) |
media_urls optional | string[] | Public https URLs. Validated against SSRF (no localhost, private IPs, etc.) |
first_comment optional | string | Posted as the first comment right after publish (Instagram, Facebook) |
tiktok_settings optional | object | TikTok-specific options (privacy, duet/stitch, commercial content, etc.) |
Example request
curl https://api.outreply.com/api/v1/posts/schedule \ -X POST \ -H "Authorization: Bearer outreply_live_..." \ -H "Content-Type: application/json" \ -d '{ "page_id": "6711...", "message": "Launching tomorrow 🚀", "scheduled_at": "2026-05-01T09:00:00Z", "media_urls": ["https://cdn.example.com/hero.jpg"], "first_comment": "More details at acme.com" }'
Response 201
{
"scheduled_post": {
"id": "68a1...",
"page_id": "6711...",
"platform": "instagram",
"scheduled_at": "2026-05-01T09:00:00.000Z",
"status": "scheduled",
"message": "Launching tomorrow 🚀",
"media": [{ "src": "https://cdn.example.com/hero.jpg", "type": "photo" }],
"first_comment": "More details at acme.com",
"created_at": "2026-04-18T12:00:00.000Z"
}
}Publish a post immediately on one of your pages. Same body as /posts/schedule minus scheduled_at. The HTTP response is only returned once the upstream platform has accepted the post, so expect multi-second latency for video uploads.
Body
| Field | Type | Description |
|---|---|---|
page_id required | string | Target page ID from /pages |
message optional* | string | Post text. Max 5 000 chars. *Either message or one media item is required. |
media_ids optional | string[] | IDs from /media/upload |
media_urls optional | string[] | Public https URLs (SSRF-validated) |
first_comment optional | string | Posted as the first comment right after publish (Instagram, Facebook) |
tiktok_settings optional | object | TikTok-specific options |
Example request
curl https://api.outreply.com/api/v1/posts/publish \ -X POST \ -H "Authorization: Bearer outreply_live_..." \ -H "Content-Type: application/json" \ -d '{ "page_id": "6711...", "message": "Live from the API 🚀", "media_urls": ["https://cdn.example.com/hero.jpg"], "first_comment": "More details at acme.com" }'
Response 201
{
"post_id": "17841...",
"platform": "IG",
"published_at": "2026-05-01T09:00:00.000Z",
"message": "Live from the API 🚀",
"permalink": "https://instagram.com/p/...",
"status": "published"
}Lists pending scheduled posts.
Query parameters
page_id optional | Filter by page |
limit optional | 1–100, default 50 |
Response 200
{
"scheduled_posts": [
{
"id": "68a1...",
"page_id": "6711...",
"platform": "instagram",
"scheduled_at": "2026-05-01T09:00:00.000Z",
"status": "scheduled",
"message": "Launching tomorrow 🚀"
}
]
}Details of a single scheduled post.
Response 200
{ "scheduled_post": { /* same shape as create response */ } }Cancels a pending post. Returns 404 if already cancelled or published.
Response 200
{ "success": true, "id": "68a1..." }Lists posts that have been published through OutReply.
Query parameters
page_id | Filter by page |
limit | 1–100, default 50 |
since | ISO-8601; only posts published after this time |
Response 200
{
"published_posts": [
{
"id": "68a1...",
"page_id": "6711...",
"platform": "instagram",
"remote_id": "17891234567890123",
"permalink": "https://www.instagram.com/p/C9x.../",
"published_at": "2026-05-01T09:00:15.000Z",
"message": "Launching tomorrow 🚀",
"metrics": { "likes": 42, "comments": 3, "shares": 1 }
}
]
}Lists comments on one of your published posts.
Query parameters
post_id required | Published post ID |
limit | 1–100, default 50 |
since | ISO-8601 — only comments created after this time |
Response 200
{
"comments": [
{
"id": "c_abc123",
"post_id": "68a1...",
"platform": "instagram",
"author": { "name": "Jane Doe", "username": "jane.doe", "profile_picture": "https://..." },
"message": "Love this!",
"created_at": "2026-05-01T09:15:00.000Z",
"replies_count": 0,
"parent_id": null
}
]
}Posts a reply to a comment.
Body
comment_id required | string |
message required | string, max 5 000 chars |
Response 201
{
"reply": {
"id": "c_xyz789",
"parent_id": "c_abc123",
"message": "Thanks 💚",
"created_at": "2026-05-01T09:16:30.000Z"
}
}Uploads a single image or video. The field name must be file (multipart/form-data).
Security & limits
- Allowed MIME types:
image/jpeg,image/png,image/gif,image/webp,video/mp4,video/quicktime,video/webm - SVG is rejected (XSS vector). HTML/PDF/ZIP/SWF are rejected.
- Magic-byte verification: if the file's bytes don't match its declared MIME, the upload is refused.
- Max per-file size: 25 MB (free) / 100 MB (pro).
- Concurrent storage: 100 MB (free) / 1 GB (pro) / 5 GB (elite).
Example request
curl https://api.outreply.com/api/v1/media/upload \ -H "Authorization: Bearer outreply_live_..." \ -F "file=@./hero.jpg"
Response 201
{
"media_id": "69b2...",
"filename": "api_d8f3c...a1.jpg",
"size_bytes": 2345678,
"type": "photo",
"mime_type": "image/jpeg",
"url": "https://api.outreply.com/assets/media/posts/uploads/api_d8f3c...a1.jpg",
"tier": "pro",
"quota": { "used_bytes": 8000000, "limit_bytes": 1073741824, "remaining_bytes": 1065741824 }
}Error responses
400 UPLOAD_ERROR | Bad multipart, disallowed extension, or disallowed MIME |
400 INVALID_FILE_CONTENT | Magic bytes don't match declared MIME (spoofed file) |
400 NO_FILE | Field file missing |
413 FILE_TOO_LARGE | Single file exceeds your tier's max |
413 QUOTA_EXCEEDED | Upload would push you over your concurrent storage quota |
Lists your active (non-deleted) uploaded media.
Response 200
{
"media": [
{
"media_id": "69b2...",
"filename": "api_d8f3c...a1.jpg",
"size_bytes": 2345678,
"type": "photo",
"mime_type": "image/jpeg",
"scheduled_post_id": null,
"created_at": "2026-04-18T12:00:00.000Z"
}
],
"tier": "pro",
"quota": { "used_bytes": 8000000, "limit_bytes": 1073741824, "remaining_bytes": 1065741824 }
}Deletes a media item. Fails with 409 MEDIA_IN_USE if the file is attached to a pending scheduled post — cancel the post first.
Response 200
{ "success": true, "media_id": "69b2..." }Integrations
The API works everywhere. Here are ready-to-copy blueprints for the most common no-code tools.
Use the built-in HTTP > Make a request module. No custom connector needed.
- Add HTTP > Make a request.
- URL:
https://api.outreply.com/api/v1/posts/schedule - Method:
POST - Headers:
Authorization: Bearer {{connection.outreply_token}},Content-Type: application/json - Body type: Raw / JSON. Map fields from upstream modules:
{
"page_id": "{{1.page_id}}",
"message": "{{1.caption}}",
"scheduled_at": "{{formatDate(1.publish_time; YYYY-MM-DDTHH:mm:ssZ)}}",
"media_urls": ["{{1.image_url}}"]
}Tip
Create a Make Connection of type Custom token so the token isn't pasted into every scenario.
Use the Webhooks by Zapier built-in action.
- Action: Webhooks by Zapier > Custom Request.
- Method:
POST. - URL:
https://api.outreply.com/api/v1/posts/schedule. - Data pass-through: No. Data: paste raw JSON and tick "JSON":
{
"page_id": "YOUR_PAGE_ID",
"message": "{{step1.caption}}",
"scheduled_at": "{{step1.iso_time}}",
"media_urls": ["{{step1.image_url}}"]
}Headers
Authorization | Bearer outreply_live_... |
Content-Type | application/json |
For scheduled comment replies, use Schedule by Zapier as the trigger, then call POST /comments/reply with the comment_id from a previous step.
Use the built-in HTTP Request node with Header Auth credentials.
- Create credential: Header Auth with name
Authorizationand valueBearer outreply_live_.... - Add an HTTP Request node: URL
https://api.outreply.com/api/v1/posts/schedule, Method POST, Body type JSON. - Combine with a Schedule Trigger + Set node to template the payload.
A one-line crontab entry that schedules tomorrow's 09:00 post with a rotating tip:
# /etc/crontab — 09:00 every day 0 9 * * * curl -sS https://api.outreply.com/api/v1/posts/schedule \ -H "Authorization: Bearer $OUTREPLY_TOKEN" \ -H "Content-Type: application/json" \ -d "{ \"page_id\": \"$PAGE_ID\", \"message\": \"$(shuf -n1 /opt/tips.txt)\", \"scheduled_at\": \"$(date -u -d 'tomorrow 09:00' +%Y-%m-%dT%H:%M:%SZ)\" }"
Coming soon
We ship incrementally. Here's what's on deck — watch this page or subscribe to the changelog.
post.published, post.failed, comment.received, comment.replied, account.quota.warning. Retries + auto-disable + secret rotation. See the Webhooks section./posts/schedule.Have a feature you need?
Email api@outreply.com — the roadmap is actively shaped by integrators.