API & developers
Selamia for developers & AI agents
A clean REST API, webhooks for every event and an MCP server: schedule posts from your website, CRM or POS, send every new Google review to Slack, or let Claude plan your week. Included in the Pro, Autopilot and Agency plans.
Included in the Pro, Autopilot and Agency plans (and during the free trial).
Overview
REST API v1
JSON, ISO dates, cursor pagination, idempotent creation, French error messages ready to show.
Webhooks for every event
14 events signed with HMAC-SHA256, automatic retries, delivery log and one-click test.
MCP server
8 tools for Claude, Cursor and any MCP client — with French key dates and your Brand Kit.
Why it's better than the usual social media APIs
- Webhooks for every event — not just publishing
- Same rules as the app: network limits, plan quotas, client approval
- Idempotency-Key: retries never create duplicates
- Safe media import from a URL (no private networks, size and type checked)
- One key per workspace and per tool: built for agencies
- Error messages in French, ready to show to your customers
Authentication
Create a key in Settings › Developers (owner or admin). Send it in the Authorization header of every request. A key belongs to one workspace and acts with the current role of the person who created it: if they leave the team, the key stops working. Only a SHA-256 hash is stored — the key is shown once.
GET /api/v1/me HTTP/1.1
Host: selamia.com
Authorization: Bearer pk_live_…| Scopes | Description |
|---|---|
| posts:read | Read posts |
| posts:write | Create & schedule posts |
| accounts:read | Read connected accounts |
| media:write | Upload media |
| stats:read | Read statistics |
| ai:write | Use AI |
Quickstart
Three calls to schedule your first post. scheduledAt accepts an ISO 8601 date with offset, "next_slot" (next free queue slot) or "now". Omit it to create a draft.
export SELAMIA_KEY="pk_live_…"
# 1. Your workspace, scopes and usage
curl https://selamia.com/api/v1/me -H "Authorization: Bearer $SELAMIA_KEY"
# 2. Your connected accounts (ids)
curl https://selamia.com/api/v1/accounts -H "Authorization: Bearer $SELAMIA_KEY"
# 3. Schedule a post on the next free slot
curl -X POST https://selamia.com/api/v1/posts \
-H "Authorization: Bearer $SELAMIA_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: menu-de-saison-2026" \
-d '{
"caption": "Our seasonal menu starts Tuesday 🍂",
"hashtags": ["lyon", "bistrot"],
"accountIds": ["<instagram-id>", "<facebook-id>"],
"mediaUrls": ["https://example.com/photos/menu.jpg"],
"scheduledAt": "next_slot",
"overrides": {
"<facebook-id>": { "caption": "Facebook version: book your table!" }
}
}'{
"object": "post",
"id": "21eef5cd-043d-4c21-aa56-9d873a29c2c2",
"status": "scheduled",
"format": "image",
"caption": "Le menu de saison arrive mardi 🍂",
"scheduledAt": "2026-10-20T10:30:00.000Z",
"targets": [
{ "network": "Instagram", "status": "scheduled", "permalink": null, "error": null },
{ "network": "Facebook", "status": "scheduled", "permalink": null, "error": null }
],
"url": "https://selamia.com/app/posts/21eef5cd-…"
}Endpoints
Base URL: https://selamia.com/api/v1
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /me | — | Workspace, key, role, plan and monthly usage |
| GET | /accounts | accounts:read | Connected accounts (formats, limits) |
| GET | /posts?from&to&status&accountId&cursor | posts:read | Posts sorted by date, cursor pagination |
| GET | /posts/:id | posts:read | A post and its per-network status |
| POST | /posts | posts:write | Draft, schedule, publish now or queue |
| PATCH | /posts/:id | posts:write | Partial update, (re)schedule |
| DELETE | /posts/:id | posts:write | Delete (upcoming publications cancelled) |
| POST | /posts/:id/retry | posts:write | Retry failed publications |
| POST | /media | media:write | File (multipart) or safe URL import |
| GET | /slots/next?accountIds&count | posts:read | Next free queue slots |
| GET | /stats/summary?period=30d | stats:read | Key figures, top posts, recommendations |
| POST | /ai/caption | ai:write | AI captions in the brand's voice (1 credit) |
| GET | /brand-kit | — | Brand identity (colors, tone, contact) |
| GET | /moments?days=45 | — | Upcoming French key dates + post ideas |
Full schemas: openapi.json (import it into Postman, Insomnia or your code generator).
Webhooks
Add an HTTPS URL in Settings › Developers, choose the events, and Selamia sends a signed POST for each one. Answer with a 2xx within 10 seconds; otherwise we retry after 1 min, 5 min, 30 min, 2 h and 12 h. After 20 consecutive failures the webhook is paused and the owner is notified. Use the event id to deduplicate.
Events
post.createdA new post (including drafts) is created.post.updatedA post's text, media, networks or date change.post.scheduledA post is scheduled (or rescheduled) for a date.post.approval_requestedA post is sent for approval (client or manager).post.approvedThe client or manager approves a post.post.changes_requestedThe client or manager asks for changes.post.publishedA post is live on a network (one delivery per network, with its link).post.failedPublishing permanently failed on a network (with the reason).post.deletedA post is deleted (its upcoming publications are cancelled).comment.receivedA new comment lands in the unified inbox.review.receivedA new Google review arrives (with its rating).account.connectedA social account is connected (or reconnected).account.expiredAn account's connection expired and must be reconnected.report.readyThe monthly PDF report has been generated.
Payload
{
"id": "evt_9mQ2xK…",
"type": "post.published",
"createdAt": "2026-10-20T10:30:04.512Z",
"workspaceId": "d4328…",
"data": {
"post": { "id": "21eef5cd-…", "status": "published", "caption": "…", "targets": [ … ] },
"target": {
"network": "Instagram",
"status": "published",
"permalink": "https://www.instagram.com/p/…",
"publishedAt": "2026-10-20T10:30:03.981Z"
}
}
}Headers: Selamia-Signature (t=timestamp,v1=HMAC-SHA256 of “t.rawBody” with your whsec_ secret), Selamia-Event, Selamia-Event-Id, Selamia-Delivery.
Verify the signature (Node.js)
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.SELAMIA_WEBHOOK_SECRET; // whsec_…
// Keep the raw body: the signature covers the exact bytes
app.post("/webhooks/selamia", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("Selamia-Signature") ?? "";
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto.createHmac("sha256", SECRET).update(`${t}.${req.body}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300; // anti-replay: 5 min
const valid = !!v1 && v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
if (!fresh || !valid) return res.status(400).send("Invalid signature");
const event = JSON.parse(req.body);
// Deduplicate with event.id, answer fast, process in the background
if (event.type === "review.received") notifySlack(event.data.item);
res.sendStatus(200);
});
app.listen(3001);MCP server for AI agents
Selamia speaks the Model Context Protocol (Streamable HTTP) at https://selamia.com/api/mcp, with the same API keys, scopes and rules. Connect it to Claude Code, Claude Desktop, Cursor or any MCP client, then ask: "Plan 3 posts for Halloween and schedule them on Instagram and Facebook at the best times."
claude mcp add --transport http selamia https://selamia.com/api/mcp \
--header "Authorization: Bearer pk_live_…"{
"mcpServers": {
"selamia": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://selamia.com/api/mcp",
"--header",
"Authorization:${SELAMIA_AUTH}"
],
"env": {
"SELAMIA_AUTH": "Bearer pk_live_…"
}
}
}
}{
"mcpServers": {
"selamia": {
"url": "https://selamia.com/api/mcp",
"headers": {
"Authorization": "Bearer pk_live_…"
}
}
}
}Tools
list_accountsList connected social accounts
list_postsRead the calendar (date / status filters)
create_postCreate a draft or schedule a post
schedule_postSchedule an existing draft
generate_captionWrite a caption in the brand's tone
get_stats_summaryStats summary for a period
list_upcoming_momentsUpcoming French key dates + ideas
get_brand_kitBrand identity (colors, tone, contact)
Agents get exactly the rights of the key: a key without posts:write cannot create posts. Drafts by default — publishing only when asked.
Rate limits & errors
120 requests per minute and per key (REST + MCP). Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 also carries Retry-After. Errors always look like { "error": { "code", "message", "details"? } }: code is stable (English), message is in French and ready to display.
{
"error": {
"code": "unprocessable",
"message": "Impossible de programmer :\n• Instagram demande au moins une image ou une vidéo.",
"details": ["Instagram demande au moins une image ou une vidéo."]
}
}| HTTP | code | Description |
|---|---|---|
| 401 | unauthorized / invalid_api_key | Missing, invalid or revoked key |
| 403 | insufficient_scope / forbidden | Missing key scope or insufficient role |
| 403 | plan_required | Plan without the developer platform |
| 400 | validation_error / invalid_json | Invalid body or parameters (per-field details) |
| 404 | not_found | Resource not in this workspace |
| 402 | limit_reached | Plan quota reached (posts, AI credits, storage) |
| 422 | unprocessable | Content refused (network rule, client approval…) |
| 429 | rate_limited | More than 120 requests / minute |
- Dates in UTC (ISO 8601); the workspace time zone comes with GET /me.
- Idempotency-Key on POST /posts: replays return the same post.
- Cursor pagination: pass nextCursor as ?cursor= until hasMore is false.
Build on Selamia today
Pick a template or type your idea to Selamia AI: your first post can be ready in minutes.
Free, with no time limit No credit card needed Autopilot free for 14 days



