BUILD WITH POSTRIVET
Developer API
Schedule text, image, or video posts using your own connected accounts. Base URL: https://postrivet.com/api/v1.
1. Connect, generate, schedule
- Sign in and connect a platform through Connections.
- Create a named key in API access. Copy it once and keep it in a secret store or environment variable.
- Call
GET /accountsand use a connected account'sidasaccountId. - Upload media if needed, then create a post. Poll the returned delivery ID to check publication.
Authorization: Bearer YOUR_POSTRIVET_API_KEY
Every request requires HTTPS and this header. Use the canonical host directly; do not rely on redirects to forward credentials. Never put a key in a URL, source control, browser JavaScript, or a distributed app. Use your own server to call PostRivet. Browser cookies alone do not authenticate this API.
Keys access only their owner's connected accounts, posts, and media. They cannot connect or disconnect social accounts, manage keys, or access administration. Existing JWT integrations continue to work. The authenticated OpenAPI document is available at GET https://postrivet.com/openapi/v1.json with the same Authorization header; it also describes legacy JWT-only connection methods.
Up to 10 active keys are allowed per user. They do not expire automatically. Revoke unused or exposed keys. Rotate to immediately replace a key, or create a second key for a gradual transition. Revocation affects subsequent authentication checks, not already authenticated requests or previously scheduled posts. Last-used time records successful authentication, even if the operation later fails.
2. Available methods
| Method & path | Purpose and result |
|---|---|
GET /accounts | Array of up to 100 accounts: id, provider, did, status. Select a Connected account. |
POST /media | Upload raw file bytes with Content-Type and Idempotency-Key. Returns media metadata including id and kind; 201 new, 200 replay. |
GET /media?after=GUID | Array of up to 100 nondeleted media records. Pass the last id as after; continue until empty. |
GET /media/{id} | Get media metadata, not file bytes. |
DELETE /media/{id} | Delete unused file bytes; returns 204. Pending publications can prevent deletion. |
POST /posts | Create a schedule using JSON and Idempotency-Key. Returns the delivery object and ETag; 201 new, 200 replay. |
GET /posts?status=Scheduled&limit=25&after=GUID | Returns items and nextCursor. Limit 1–100. Pass nextCursor as after; stop on an empty items array. |
GET /posts/{id} | Returns delivery and content, with ETag. Use the delivery id, not postId. |
PUT /posts/{id} | Replace accountId, content and schedule with the same JSON shape as creation. Requires If-Match. Returns updated delivery and ETag. |
POST /posts/{id}/cancel | Cancel a pending delivery; no body required. Requires If-Match. Returns delivery and new ETag. |
GET /posts/{id}/attempts?before=TIMESTAMP | Up to 100 attempts, newest first. Optional before is an exclusive UTC timestamp filter; it is not a unique cursor when timestamps tie. |
The scheduling JSON contains accountId, content, and schedule. For an absolute time use schedule.instant with a UTC ISO-8601 value ending in Z. Alternatively send localTime and an IANA timeZone, such as America/Chicago. For repeated daylight-saving times, provide disambiguation as earlier or later. Do not combine instant and local-time fields.
Store the delivery object's id. A successful create response means scheduled, not published. Statuses include Scheduled, Retry, Publishing, Reconciling, Uncertain, Published, Cancelled, Expired, Failed, and ReconnectRequired. Check delivery status and providerUrl; reconnect through the website if required. Do not create another post merely because an existing result is Uncertain.
3. cURL examples
These examples use Bash syntax and require curl and jq. Set POSTRIVET_API_KEY securely outside your script. Replace ACCOUNT_ID and choose a future UTC time. On Windows, use the C# example below or adapt the commands for PowerShell.
BASE='https://postrivet.com/api/v1'
curl --fail-with-body "$BASE/accounts" \
-H "Authorization: Bearer $POSTRIVET_API_KEY"
# Save this payload as text-post.json; replace the account and future time.
# {"accountId":"ACCOUNT_ID","content":{"text":"Hello from my integration!"},
# "schedule":{"instant":"2027-04-01T15:00:00Z"}}
curl --fail-with-body -i "$BASE/posts" \
-H "Authorization: Bearer $POSTRIVET_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: text-example-001' --data-binary @text-post.json
Image post
Upload raw bytes, then reference the returned id in content.attachments. Use a fresh idempotency key for each distinct operation.
MEDIA_ID=$(curl --fail-with-body "$BASE/media" \
-H "Authorization: Bearer $POSTRIVET_API_KEY" \
-H 'Content-Type: image/jpeg' -H 'Idempotency-Key: image-upload-001' \
--data-binary @photo.jpg | jq -r '.id')
jq -n --arg media "$MEDIA_ID" \
'{accountId:"ACCOUNT_ID",content:{text:"A moment worth sharing",
attachments:[{id:$media,order:0,kind:"image",altText:"Describe the image"}]},
schedule:{instant:"2027-04-01T15:00:00Z"}}' > image-post.json
curl --fail-with-body "$BASE/posts" \
-H "Authorization: Bearer $POSTRIVET_API_KEY" \
-H 'Content-Type: application/json' -H 'Idempotency-Key: image-post-001' \
--data-binary @image-post.json
Video post
MEDIA_ID=$(curl --fail-with-body "$BASE/media" \
-H "Authorization: Bearer $POSTRIVET_API_KEY" \
-H 'Content-Type: video/mp4' -H 'Idempotency-Key: video-upload-001' \
--data-binary @clip.mp4 | jq -r '.id')
jq -n --arg media "$MEDIA_ID" \
'{accountId:"ACCOUNT_ID",content:{text:"A short update",
attachments:[{id:$media,order:0,kind:"video",altText:"Describe the clip"}]},
schedule:{instant:"2027-04-01T16:00:00Z"}}' > video-post.json
curl --fail-with-body "$BASE/posts" \
-H "Authorization: Bearer $POSTRIVET_API_KEY" \
-H 'Content-Type: application/json' -H 'Idempotency-Key: video-post-001' \
--data-binary @video-post.json
Inspect, edit, or cancel
Read the latest ETag response header first (for example "1"). Supply it exactly, including quotes, in If-Match. PUT replaces the complete scheduling payload, including attachments. Only Scheduled or Retry deliveries can be edited or cancelled.
curl -i "$BASE/posts/DELIVERY_ID" -H "Authorization: Bearer $POSTRIVET_API_KEY"
curl --fail-with-body -X PUT "$BASE/posts/DELIVERY_ID" \
-H "Authorization: Bearer $POSTRIVET_API_KEY" -H 'If-Match: "1"' \
-H 'Content-Type: application/json' --data-binary @updated-post.json
# Fetch the new ETag before cancelling; "2" below is only an example.
curl --fail-with-body -X POST "$BASE/posts/DELIVERY_ID/cancel" \
-H "Authorization: Bearer $POSTRIVET_API_KEY" -H 'If-Match: "2"'4. C# example (.NET)
This console example lists your accounts, optionally uploads one image or video, schedules a post ten minutes ahead, and fetches its status. Set POSTRIVET_API_KEY and POSTRIVET_ACCOUNT_ID in your environment. Set POSTRIVET_MEDIA_PATH and POSTRIVET_MEDIA_TYPE (image/jpeg, image/png, image/webp, or video/mp4) to attach media; omit both for text only. Never print the API key.
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
var key = Environment.GetEnvironmentVariable("POSTRIVET_API_KEY")
?? throw new InvalidOperationException("Set POSTRIVET_API_KEY.");
using var http = new HttpClient { BaseAddress = new Uri("https://postrivet.com/api/v1/") };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", key);
using var accounts = await http.GetAsync("accounts");
accounts.EnsureSuccessStatusCode();
Console.WriteLine(await accounts.Content.ReadAsStringAsync());
var accountId = Guid.Parse(Environment.GetEnvironmentVariable("POSTRIVET_ACCOUNT_ID")
?? throw new InvalidOperationException("Choose a connected account ID from the list."));
var attachments = new List<object>();
var path = Environment.GetEnvironmentVariable("POSTRIVET_MEDIA_PATH");
if (!string.IsNullOrWhiteSpace(path))
{
var mime = Environment.GetEnvironmentVariable("POSTRIVET_MEDIA_TYPE")
?? throw new InvalidOperationException("Set POSTRIVET_MEDIA_TYPE.");
using var upload = new HttpRequestMessage(HttpMethod.Post, "media");
upload.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
upload.Content = new StreamContent(File.OpenRead(path));
upload.Content.Headers.ContentType = new MediaTypeHeaderValue(mime);
using var uploaded = await http.SendAsync(upload);
uploaded.EnsureSuccessStatusCode();
using var media = JsonDocument.Parse(await uploaded.Content.ReadAsStringAsync());
attachments.Add(new { id = media.RootElement.GetProperty("id").GetGuid(), order = 0,
kind = mime == "video/mp4" ? "video" : "image", altText = "Describe your media" });
}
// For production retries, persist this key and payload before the first request.
var operationKey = Guid.NewGuid().ToString();
var payload = new { accountId, content = new { text = "Hello from C#!", attachments },
schedule = new { instant = DateTime.UtcNow.AddMinutes(10).ToString("O") } };
using var request = new HttpRequestMessage(HttpMethod.Post, "posts");
request.Headers.Add("Idempotency-Key", operationKey);
request.Content = JsonContent.Create(payload);
using var response = await http.SendAsync(request);
response.EnsureSuccessStatusCode();
using var result = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
var deliveryId = result.RootElement.GetProperty("id").GetGuid();
using var status = await http.GetAsync($"posts/{deliveryId}");
status.EnsureSuccessStatusCode();
Console.WriteLine(await status.Content.ReadAsStringAsync());5. Limits, retries, and errors
- 120 API requests per minute per owner per application instance, shared across that owner's keys. Media uploads also share a server concurrency limit.
- Text: at most 300 grapheme clusters and 3,000 UTF-8 bytes. Text may be empty only when media is attached.
- Attach 1–4 images or one video; no mixed image/video post. Attachment order starts at 0 and must be consecutive. Optional altText is at most 2,000 characters. Optional width and height must both be supplied and positive.
- JPEG, PNG, WebP: up to 2,000,000 bytes each. MP4: up to 25,000,000 bytes. Send raw bytes, not multipart, JSON, base64, or remote URLs. Platform-specific encoding and duration rules also apply; upload acceptance is not a publication guarantee.
- Media storage: 100,000,000 bytes per owner, 512,000,000 bytes shared by the service. Delete unused uploads to free capacity.
- JSON request bodies: up to 32,768 bytes. Schedules require at least five seconds of lead time; allow more for network delays.
Supply an Idempotency-Key of 1–128 characters for POST /posts and POST /media. Generate one per logical operation and keep both the key and payload unchanged when retrying. A changed payload with the same key returns 409. Persist your request and key before sending so retries after process restarts are safe. An idempotent replay returns the existing resource.
Errors use HTTP status codes and generally return application/problem+json with title, detail, status, and traceId. Hosting-layer failures may have a different body. Keep traceId for support; do not share credentials.
| Status | Action |
|---|---|
| 400 / 422 | Correct invalid JSON, scheduling fields, content, or file format. |
| 401 | Missing, invalid, revoked key, or unavailable/locked account. Check credentials; do not retry endlessly. |
| 403 | This credential cannot perform the operation. |
| 404 | Resource does not exist or belongs to another user. |
| 409 | Idempotency conflict, media in use/storage full, or publication already begun. |
| 410 | The upload associated with that idempotency key was deleted; use a new key for a new upload. |
| 412 / 428 | ETag is stale / If-Match is missing or invalid. Fetch again and review before retrying. |
| 413 / 415 | Request/file too large or unsupported Content-Type. |
| 429 / 5xx | Back off with jitter; honor Retry-After if supplied. Retry creations using the same idempotency key and payload. For edits/cancellation, fetch status first. |
API access is subject to the Terms of Service and Privacy Policy.