Getting started
Generate an API key from Settings → Developer. Keys scope to one workspace by default. Include the key as a Authorization: Bearer header on every request. TLS is enforced; HTTP is rejected.
curl https://api.usealoha.app/v1/posts \
-H "Authorization: Bearer alo_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"content": "a monday note.",
"channels": ["instagram", "linkedin"],
"scheduledAt": "2026-04-15T09:30:00Z"
}'The response carries the created post's ID and its per-channel status. You can read it back at GET /v1/posts/:id.
Authentication
Two authentication modes: API keys for first-party use, OAuth 2.0 (authorization code + PKCE) for partner apps. Rotate keys any time; we honour the old key for 24 hours for graceful deploys.
API keys
alo_live_* and alo_test_*. Workspace-scoped.
OAuth 2.0
Partner apps. PKCE required. Scopes: read, write, webhook:admin.
REST endpoints
/v1/postsCreate a scheduled or drafted post./v1/posts/:idRead a post and its per-channel status./v1/postsList posts with filters by channel, status, date./v1/analytics/exportKick off an analytics export (CSV / JSON)./v1/inbox/threadsList unified inbox threads./v1/matrix/:id/runTrigger a matrix run manually./v1/voice/trainSubmit training set for the voice model.Webhooks
Subscribe to event types in Settings → Webhooks. Every payload is signed with HMAC-SHA256 under a secret you control. We retry failed deliveries 6 times with exponential backoff (1m, 5m, 25m, 2h, 12h, 24h).
POST /your-endpoint
X-Aloha-Signature: sha256=<hmac>
X-Aloha-Event: post.published
{
"id": "evt_01HZ...",
"event": "post.published",
"created": 1712620800,
"data": { "postId": "post_01HY...", "channel": "instagram" }
}Events currently shipped: post.scheduled, post.published, post.failed, reply.received, matrix.completed.
SDKs
First-party SDKs for TypeScript and Python, both open source on GitHub. The SDK is a thin wrapper — you can always drop down to raw HTTP.
// TypeScript
import { Aloha } from "@aloha/sdk";
const client = new Aloha({ apiKey: process.env.ALOHA_KEY });
await client.posts.create({
content: "a monday note.",
channels: ["instagram"],
scheduledAt: new Date("2026-04-15T09:30:00Z"),
});Rate limits
Every plan gets different generous-but-honest limits. Free: 60 req/min. Working Team: 600 req/min. Agency: 3,000 req/min. Each response carries X-RateLimit-* headers so you never have to guess.
If you hit a 429, back off by the value of the Retry-After header. We don't shadow-throttle; a 429 is a 429.