Relay docs
What Relay does
Publishing to Instagram or TikTok from an API is more involved than one HTTP call. You need reviewed developer apps, tokens that expire (60 days on Instagram, 24 hours on TikTok), publicly reachable media URLs, an asynchronous create → poll → publish handshake, and per-account caps that silently stop you — 100 posts a day on Instagram, about 15 on TikTok. Relay owns all of that.
- Connections. OAuth with Instagram Login and TikTok Login Kit, tokens encrypted at rest (AES-256-GCM) and refreshed automatically before they expire.
- Media. Upload bytes, send base64 inline (over the API or MCP), or hand Relay a public URL; it validates the format, dimensions and video length against each platform's rules and hosts the file for you. Agents holding a local file with no public URL to offer can park it at POST /v1/uploads and pass back the short-lived link it returns.
- Scheduling. A scheduler claims due posts every minute, so "publish now" and "publish next Tuesday at 09:00" are the same code path.
- Delivery. Instagram containers and carousel children, TikTok video and photo posts (straight to the profile or into the TikTok inbox), status polling, retries on transient errors, and a per-account outcome you can read back — with the platform's own error code and message when something is rejected.
One post can target several accounts. Each target succeeds or fails independently, which is why a post can end up partly published.
tiktok object — who can view the post, which interactions are allowed, and any commercial disclosure — because TikTok requires the creator to choose those. See TikTok requirements.Core objects
Five objects carry the whole model. Every one of them is scoped to your account.
| Object | What it is |
|---|---|
| account | A connected Instagram or TikTok profile. Carries the encrypted tokens, connection health, token expiry, and cached follower/media counts. Its id is what you pass as a post target. |
| media | An image or video stored by Relay and served from a public URL — which is what Instagram and TikTok fetch at publish time. Reusable across posts. |
| post | A caption, an ordered list of media, a post type, TikTok settings when it targets TikTok, and a schedule. Carousel slides can each carry their own caption on top of the post’s. Holds the roll-up status across all its targets. |
| target | One post ↔ one account. Owns the real outcome: the platform’s post ID, the permalink, and the error if it failed. |
| api key | A rly_live_… secret that authorizes both the REST API and the MCP server. Only a SHA-256 hash is stored, so a lost key can be revoked but never recovered. |
Publishing lifecycle
Creating a post never blocks on Instagram. The API validates and queues; a scheduler running every minute does the work. That means a successful POST /v1/posts means "accepted", not "live" — read the post back to find out what happened.
create ─► scheduled ──(scheduler claims it)──► publishing ─┬─► published all targets ok
├─► partly some ok, some failed
└─► failed every target failed
per target: pending ─► uploading (carousel children) ─► processing ─► published
└─► failedImages usually finish inside the tick that claims them. Video is slower: Instagram transcodes asynchronously, so the target sits in processing and Relay re-checks it on later ticks. Transient Instagram errors (429s, 5xx) don't fail a post — they're retried. See Timing & retries for the exact budgets.
Quickstart
Five minutes from nothing to a scheduled post.
1. Create an API key
In the dashboard, go to API keys and create one. The full value is shown exactly once — store it in your secret manager. The same key authorizes the REST API and the MCP server.
2. Connect an account
Go to Accounts → Connect account and pick Instagram or TikTok. An Instagram account must be a professional one (Business or Creator); personal accounts are rejected during the connect flow, not at publish time. Any TikTok account works.
3. Find the account ID
curl https://api.relay.lantean.tech/v1/accounts \ -H "Authorization: Bearer $RELAY_API_KEY"
{
"accounts": [
{
"id": "9d1f2c34-5b6a-4c8d-9e0f-1a2b3c4d5e6f",
"platform": "instagram",
"username": "northlight.co",
"status": "connected",
"followersCount": 12840
}
]
}4. Schedule a post
Media can be a public URL — Relay fetches and stores it — or an ID from an earlier upload. Omit schedule_at to publish on the next tick instead.
curl -X POST https://api.relay.lantean.tech/v1/posts \
-H "Authorization: Bearer $RELAY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: fall-drop-2026-08-04" \
-d '{
"targets": ["9d1f2c34-5b6a-4c8d-9e0f-1a2b3c4d5e6f"],
"caption": "Fall drop is live — link in bio.",
"media": ["https://cdn.example.com/fall-drop.jpg"],
"schedule_at": "2026-08-04T18:30:00Z"
}'5. Check what happened
curl https://api.relay.lantean.tech/v1/posts/<post_id> \ -H "Authorization: Bearer $RELAY_API_KEY"
Each entry in targets carries its own status, the permalink once live, and an error object with the platform's code and message when it isn't.
Limits at a glance
| Limit | Value | Where it comes from |
|---|---|---|
| API requests | 120 / minute per key | Relay |
| Failed auth attempts | 30 / minute per IP | Relay |
| Published posts | 100 / rolling 24h per account | |
| Published posts | ~15 / day per creator, across all apps; 5 waiting inbox uploads | TikTok |
| Caption | 1–2,200 characters | |
| Per-slide caption | 1–2,200 characters, carousel slides only | |
| Carousel items | 2–10 | |
| Photo post images | 1–35 (images only) | TikTok |
| Video length | The creator’s limit: 3, 5 or 10 minutes | TikTok |
| Image | JPEG, ≤ 8 MB, 4:5 – 1.91:1 (the dashboard converts and fits other formats for you) | |
| Video | MP4 / MOV, ≤ 100 MB | Relay (Instagram allows more) |
| Schedule granularity | ~60 seconds | Relay scheduler |
| Idempotency replay window | 24 hours | Relay |
Support
Questions, bug reports, and access requests go to support@lantean.tech. When reporting a failed publish, include the post ID and the error.code from the target — that's enough to trace it end to end.