Accounts
Create a connect link
Create a one-time hosted link your user opens to connect a social account through OAuth, without a Relaycast login.
POST https://social-publish-api.onrender.com/v1/accounts/connect-linksLets your own users connect their social accounts to your project from inside your app. You create a link, send your user to its url, they approve access on the platform's consent screen, and Relaycast sends them back to your redirectUrl with the result. Your users never need a Relaycast account.
- Your server calls this endpoint and gets a
url. - Your app redirects the user (or opens a popup) to that
url. - The user signs in to the platform and approves access.
- Relaycast redirects to your
redirectUrlwithstatus=connectedand the newaccountId, orstatus=errorand anerrorcode. - Publish to the account with its
id, as with any other account.
A link works once and expires after expiresInMinutes. Create a new link each time a user wants to connect. To show your own app name and logo on the consent screen instead of Relaycast's, connect through your own OAuth app with oauthAppId.
Treat the url like a password until it's used: anyone who opens it can connect an account to your project. Create links on your server, never in client-side code, so your API key stays private.
Headers
| Header | Required | Description |
|---|---|---|
x-access-key | Yes* | Your API key. *Or send Authorization: Bearer <key>. |
content-type | Yes | application/json |
Body
| Field | Type | Required | Description |
|---|---|---|---|
platform | string | Yes | Any OAuth platform, for example youtube, facebook, instagram, linkedin, tiktok. Bluesky uses Connect Bluesky instead. |
redirectUrl | string | Yes | Where to send the user when they're done. Must be https (http is allowed for localhost only). Up to 2,048 characters. Your own query parameters are kept. |
state | string | No | Any value up to 500 characters, returned unchanged to redirectUrl. Use it to match the result to your user or session. |
groupId | string | No | Put the new account(s) in this social group. |
oauthAppId | string | No | Connect through one of your project's own OAuth apps for this platform. |
via | string | No | Alternative connect flow. facebook connects Instagram through Facebook Login (Instagram professional accounts linked to a Facebook Page). |
expiresInMinutes | integer | No | 5 to 10,080 (7 days). Default 60. |
Request
curl -X POST https://social-publish-api.onrender.com/v1/accounts/connect-links \
-H "x-access-key: $RELAYCAST_API_KEY" \
-H "content-type: application/json" \
-d '{ "platform": "youtube", "redirectUrl": "https://app.example.com/integrations/done", "state": "user_42" }'const res = await fetch("https://social-publish-api.onrender.com/v1/accounts/connect-links", {
method: "POST",
headers: {
"x-access-key": process.env.RELAYCAST_API_KEY!,
"content-type": "application/json",
},
body: JSON.stringify({
platform: "youtube",
redirectUrl: "https://app.example.com/integrations/done",
state: "user_42",
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { data: link } = await res.json();
// Send your user to link.urlimport os, requests
res = requests.post(
"https://social-publish-api.onrender.com/v1/accounts/connect-links",
headers={"x-access-key": os.environ["RELAYCAST_API_KEY"]},
json={"platform": "youtube", "redirectUrl": "https://app.example.com/integrations/done", "state": "user_42"},
)
res.raise_for_status()
link = res.json()["data"] # send your user to link["url"]Response
{
"data": {
"id": "5b0c7e1a-2f3d-4c5b-8a9e-1d2c3b4a5f6e",
"url": "https://social-publish-kappa.vercel.app/connect/3q2-Xb8…",
"platform": "youtube",
"status": "pending",
"accountIds": [],
"error": null,
"errorDetail": null,
"redirectUrl": "https://app.example.com/integrations/done",
"state": "user_42",
"groupId": null,
"oauthAppId": null,
"expiresAt": "2026-11-02T10:00:00.000Z",
"completedAt": null,
"createdAt": "2026-11-02T09:00:00.000Z"
}
}The url is only returned here. Relaycast stores a hash of it, so it can't be shown again.
Back at your redirectUrl
Relaycast adds these query parameters:
| Parameter | When | Description |
|---|---|---|
status | Always | connected or error. |
connectLinkId | Always | The link's id. |
platform | Always | The platform from the link. |
accountId | Connected | The connected account's id. |
accountIds | Connected | Comma-separated ids. One login can grant several accounts, for example several Facebook Pages. |
error | Error | One of the codes below. |
detail | Sometimes | The platform's own explanation, when it gave one. |
state | If you sent one | Your state, unchanged. |
https://app.example.com/integrations/done?connectLinkId=5b0c7e1a-…&platform=youtube&status=connected&accountId=7c6b5a49-…&accountIds=7c6b5a49-…&state=user_42Don't rely on the query string alone for anything sensitive: confirm with Get a connect link from your server.
error | Meaning |
|---|---|
access_denied | The user cancelled on the consent screen. |
link_expired | The link expired before it was used. Create a new one. |
link_used | The link was already used. Create a new one. |
no_accounts | The login worked but had nothing to publish to (for example, a Facebook user with no Pages). |
connect_failed | The platform rejected the connection, or the project's account limit was reached. See detail. |
provider_error | The platform returned an error. See detail. |
not_configured / app_not_configured | The platform (or your OAuth app) is missing credentials on the server. |
invalid_group / invalid_app | The group or OAuth app was deleted after the link was created. |
Errors
| Status | Code | When |
|---|---|---|
400 | validation_error | A field is missing or invalid, for example an http redirect that isn't localhost. |
400 | unsupported_platform | The platform can't be connected with a link (Bluesky). |
403 | project_suspended | The project is suspended. |
This page is also available as Markdown.