REST API reference
The TimeToPost REST API is the same API the web dashboard uses β everything you can click, you can script. All requests are JSON over HTTPS against https://timetopost.co/api, scoped to your active organization, and subject to the same plan limits and validation as the dashboard.
Authentication
Create a personal API token in the dashboard under Settings β API. Tokens look like ttp_ followed by 48 hex characters, can optionally expire after 1β365 days, and are shown exactly once at creation β only a hash is stored, so copy it immediately. Send it as a Bearer token on every request:
Authorization: Bearer ttp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxTwo safety properties to know: a token acts with your full account permissions, and β deliberately β API tokens cannot create or revoke other tokens. Token management is browser-session only, so a leaked token can never mint replacements. Revoke tokens any time from the same Settings β API page.
Posts
GET/api/posts
Lists all posts in your active organization, newest first. Each post includes id, content, platforms, status (lowercase: draft, scheduled, publishing, published, failed, partial), scheduledAt, publishedAt and mediaUrls.
curl https://timetopost.co/api/posts \
-H "Authorization: Bearer ttp_your_token_here"
# { "success": true, "posts": [ { "id": "...", "status": "scheduled", ... } ] }POST/api/posts
Creates a post. Target accounts either by accountIds (specific connected accounts β integration ids from GET /api/integrations) or by platforms (e.g. ["instagram", "twitter"]). scheduledAt must be a valid ISO 8601 timestamp in the future; requests with a past time are rejected with a validation error. Omit it to save a draft. Returns 201 with the created post.
curl -X POST https://timetopost.co/api/posts \
-H "Authorization: Bearer ttp_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"content": "Launch day! π",
"accountIds": ["cmb8x2k4p0001..."],
"mediaUrls": ["https://media.timetopost.co/uploads/launch.jpg"],
"thread": ["Tweet 2 of your X threadβ¦", "Tweet 3 β up to 24 parts, 280 chars each"],
"scheduledAt": "2026-07-01T15:00:00.000Z"
}'Also available: GET /api/posts/:id (fetch one), DELETE /api/posts/:id (delete/cancel before it fires).
Analytics
GET/api/analytics/optimal-times
Returns your best posting times computed from your own engagement history. Optional ?platform= query parameter (e.g. instagram, tiktok, twitter) narrows the analysis to one platform. Requires a plan with the best-time-to-post feature.
curl "https://timetopost.co/api/analytics/optimal-times?platform=instagram" \
-H "Authorization: Bearer ttp_your_token_here"
# {
# "success": true,
# "recommendation": {
# "bestHours": [ { "hour": 18, "score": 0.92 }, ... ], // top 5
# "bestDays": [ { "day": "Tuesday", "score": 0.88 }, ... ], // top 3
# "dataPoints": 64,
# "message": "..."
# }
# }Related endpoints: GET /api/analytics/optimal-times/by-account (per connected account), GET /api/analytics/next-optimal-time (the next best slot from now), GET /api/analytics/weekly-schedule, and GET /api/analytics/engagement-summary for aggregate likes, comments, shares and views.
Media uploads
POST/api/media/presign
Media is uploaded directly to storage with a short-lived presigned URL β your file never proxies through the API and storage credentials never reach the client. Three steps: request a presigned URL, PUT the file to it, then use the returned publicUrl in a postβs mediaUrls.
# 1. Request a presigned upload URL
curl -X POST https://timetopost.co/api/media/presign \
-H "Authorization: Bearer ttp_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "filename": "launch.jpg", "contentType": "image/jpeg", "size": 482133 }'
# { "success": true, "key": "...", "uploadUrl": "https://...",
# "publicUrl": "https://...", "expiresIn": 300 }
# 2. Upload the file
curl -X PUT "<uploadUrl>" -H "Content-Type: image/jpeg" --data-binary @launch.jpg
# 3. Reference publicUrl in POST /api/posts mediaUrlsThe body requires filename, contentType and size; uploads are validated for type and size before a URL is issued.
Errors
Errors use conventional HTTP status codes β 400 validation, 401 missing/invalid token, 403 plan or permission limits, 404 not found (including posts owned by other organizations) β with a JSON body containing success: false and a message.
Prefer working from an AI agent instead of raw HTTP? The MCP server wraps these endpoints as tools for Claude, Cursor and friends.