Base address
https://app.solmarrow.com/api/v1 — JSON in and out. The full description is at openapi.json (OpenAPI 3.1).
Sign in (OAuth 2.0)
- Authorization code flow:
https://app.solmarrow.com/oauth/authorizeandhttps://app.solmarrow.com/oauth/token, scopesolmarrow. The person sees SolMarrow's consent screen and can remove your app any time in Settings. - Partner apps get a client ID and secret from SolMarrow (secret sent as HTTP Basic or in the form; PKCE optional). Apps without a server use PKCE (S256) and dynamic client registration, as listed in
https://app.solmarrow.com/.well-known/oauth-authorization-server. - Access tokens last an hour; refresh tokens 30 days and change on every refresh (reusing an old one ends the session). Send
Authorization: Bearer …on every call. - Your own n8n or script: create a client ID and secret in SolMarrow under Settings, Apps and AI agents, Your own apps. A public app for everyone: ask for a client ID at [email protected] with its name and redirect addresses.
Endpoints
| Method | Path | What it does |
|---|---|---|
| GET | /me | The signed-in person and your app |
| GET | /workspaces | Workspaces, with their time zones |
| GET | /workspaces/{id}/accounts | Connected social accounts and each network's posting rules |
| GET | /workspaces/{id}/posts | Posts, newest first (status, from, to, limit) |
| POST | /workspaces/{id}/posts | Save a draft, schedule a post, or publish now |
| GET | /posts/{id} | One post with its accounts, status, links and results |
| DELETE | /posts/{id} | Delete a draft, scheduled or failed post |
| GET | /workspaces/{id}/media | Recent files in the media library |
| POST | /workspaces/{id}/media/from-url | Copy an image or video from a public link |
| POST | /workspaces/{id}/media/uploads | Start a direct upload (returns a link to PUT the file to) |
| POST | /workspaces/{id}/media/uploads/complete | Add a finished upload to the library |
| GET | /workspaces/{id}/analytics | Likes, comments, shares and views of published posts |
| GET / POST | /workspaces/{id}/webhooks | Your app's webhooks; subscribe to post events |
| DELETE | /webhooks/{id} | Unsubscribe |
Posts
Without schedule_at a post is saved as a draft. With it, the post is scheduled (at least 5 minutes ahead, at most a year) and shows in the person's calendar. publish_now: true publishes right away; use it only when the person pressed a publish button in your app. Each account's text is checked against its network's rules first, and the answer says what to fix. TikTok posts can only be saved as drafts here, because TikTok requires choices made in SolMarrow's composer.
POST https://app.solmarrow.com/api/v1/workspaces/{workspace_id}/posts
Authorization: Bearer smat_…
Content-Type: application/json
{
"text": "Our spring collection is live.",
"account_ids": ["…", "…"],
"media_ids": ["…"],
"schedule_at": "2026-11-03T09:00:00+06:00"
}Webhooks
Subscribe a workspace to post.scheduled, post.published or post.failed with POST /workspaces/{id}/webhooks and a public https url. The answer includes a secret, shown once. Each delivery is a POST with {id, event, created_at, workspace_id, post} and the headers SolMarrow-Event, SolMarrow-Delivery and SolMarrow-Signature. Answer with any 2xx. Other answers are retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours; answer 410 to unsubscribe.
import { createHmac, timingSafeEqual } from "node:crypto";
// header: the SolMarrow-Signature value, body: the raw request body, secret: from subscribing
export function verify(header, body, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // older than 5 minutes
const expected = createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");
return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Limits and errors
- 120 requests a minute per connected app, and 300 new posts a day per person across all apps and agents.
- Errors come as
{"error": {"status", "message"}}with the HTTP status: 401 sign in again, 404 not found in this person's workspaces, 409 the post changed (for example it's publishing), 422 fix the input, 429 slow down. - Media: JPG, PNG, WebP, GIF, MP4, MOV and WebM, counted against the workspace's storage.