Backend Integration Guide
This guide explains how to integrate Outstand into your backend and manage social media IDs in your database. By the end, you'll have a clear picture of the data flow and a recommended schema for storing Outstand resources.
Integration Overview
Key Concepts
Outstand has three main resources you need to track in your backend:
| Resource | What it represents | When you get it |
|---|---|---|
| Social Network | Your OAuth app configuration (e.g., your X app, your Facebook app) | When you call POST /v1/social-networks |
| Social Account | A user's connected account (e.g., @john on X) | When a user completes the OAuth flow |
| Post | A piece of content published to one or more accounts | When you call POST /v1/posts |
Step-by-Step Integration
1. Store your OAuth credentials
Register your OAuth app credentials with Outstand. You typically do this once per social platform.
curl -X POST https://api.outstand.so/v1/social-networks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"network": "x",
"client_key": "your_oauth_client_id",
"client_secret": "your_oauth_client_secret"
}'Save the returned id - this is your socialNetworkId. Store it in your database mapped to the platform name.
2. Connect user accounts
When a user wants to connect their social account, get an authorization URL and redirect them:
curl -X GET https://api.outstand.so/v1/social-networks/{socialNetworkId}/auth-url \
-H "Authorization: Bearer YOUR_API_KEY"After the user authorizes, Outstand handles the OAuth callback. The new social account becomes available via the API (and via webhook if configured).
3. Retrieve and store social account IDs
After a user connects their account, list your social accounts to get the new entry:
curl -X GET https://api.outstand.so/v1/social-accounts \
-H "Authorization: Bearer YOUR_API_KEY"Save the returned id for each account. This socialAccountId is what you'll use to create posts.
4. Create posts
Use the stored socialAccountIds to publish content:
curl -X POST https://api.outstand.so/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"containers": [
{ "content": "Hello world!" }
],
"socialAccountIds": ["acc_123", "acc_456"]
}'Save the returned postId and the per-account platformPostIds for tracking publish status and analytics.
Recommended Database Schema
Here's a recommended schema for storing Outstand resource IDs alongside your own data. Adapt this to your ORM and database.
SQL Example
-- Map your users/orgs to Outstand social networks
CREATE TABLE social_networks (
id SERIAL PRIMARY KEY,
outstand_network_id VARCHAR(255) NOT NULL, -- ID from Outstand
platform VARCHAR(50) NOT NULL, -- 'x', 'facebook', 'instagram', etc.
created_at TIMESTAMP DEFAULT NOW()
);
-- Map connected accounts to your users
CREATE TABLE social_accounts (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
outstand_account_id VARCHAR(255) NOT NULL, -- ID from Outstand
platform VARCHAR(50) NOT NULL,
username VARCHAR(255),
connected_at TIMESTAMP DEFAULT NOW()
);
-- Track posts and their publish status
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id),
outstand_post_id VARCHAR(255) NOT NULL, -- ID from Outstand
content TEXT,
scheduled_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW()
);
-- Track per-account publish results
CREATE TABLE post_accounts (
id SERIAL PRIMARY KEY,
post_id INTEGER NOT NULL REFERENCES posts(id),
outstand_account_id VARCHAR(255) NOT NULL,
platform_post_id VARCHAR(255), -- Native platform post ID
status VARCHAR(20) DEFAULT 'pending', -- 'pending', 'published', 'failed'
error TEXT,
published_at TIMESTAMP
);TypeScript Example (Prisma)
model SocialNetwork {
id String @id @default(cuid())
outstandNetworkId String @unique
platform String
createdAt DateTime @default(now())
}
model SocialAccount {
id String @id @default(cuid())
userId String
outstandAccountId String @unique
platform String
username String?
connectedAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
}
model Post {
id String @id @default(cuid())
userId String
outstandPostId String @unique
content String?
scheduledAt DateTime?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
postAccounts PostAccount[]
}
model PostAccount {
id String @id @default(cuid())
postId String
outstandAccountId String
platformPostId String?
status String @default("pending")
error String?
publishedAt DateTime?
post Post @relation(fields: [postId], references: [id])
}Keeping Data in Sync
Option A: Webhooks (Recommended)
Configure webhooks to receive real-time updates. This is the best approach for keeping your database in sync:
post.published- Update post status and storeplatformPostIdpost.error- Record errors for failed publishes
// Example webhook handler
app.post('/webhooks/outstand', async (req, res) => {
const event = req.body;
switch (event.event) {
case 'post.published':
for (const account of event.data.socialAccounts) {
await db.postAccount.update({
where: { outstandAccountId: account.id },
data: {
status: account.error ? 'failed' : 'published',
platformPostId: account.platformPostId,
error: account.error ?? null,
publishedAt: account.publishedAt,
},
});
}
break;
case 'post.error':
for (const account of event.data.socialAccounts) {
await db.postAccount.update({
where: { outstandAccountId: account.id },
data: { status: 'failed', error: account.error },
});
}
break;
}
res.status(200).send('OK');
});Option B: Polling
If you can't use webhooks, poll the post status endpoint:
async function checkPostStatus(outstandPostId: string) {
const res = await fetch(
`https://api.outstand.so/v1/posts/${outstandPostId}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);
const { post } = await res.json();
for (const account of post.socialAccounts) {
await db.postAccount.update({
where: { outstandAccountId: account.id },
data: {
status: account.status,
platformPostId: account.platformPostId,
error: account.error,
publishedAt: account.publishedAt,
},
});
}
}Complete Integration Flow
Best Practices
-
Always store Outstand IDs: Save
socialNetworkId,socialAccountId, andpostIdin your database. These are stable identifiers you'll need for all subsequent API calls. -
Map accounts to your users: Maintain a relationship between your user records and their connected social accounts. This lets you show users which accounts they have connected and target posts to specific accounts.
-
Use webhooks over polling: Webhooks give you real-time updates without the overhead of repeated API calls. See the webhooks documentation for setup.
-
Store platform post IDs: The
platformPostIdreturned after publishing is the native ID on the social platform (e.g., the tweet ID on X). Store this for analytics, deep linking, or comment management. -
Handle partial failures: A post can succeed on some accounts and fail on others. Always check the per-account status rather than assuming all-or-nothing. See Post Lifecycle for details.
-
Index Outstand IDs: Add database indexes on columns storing Outstand IDs (
outstand_network_id,outstand_account_id,outstand_post_id) for fast lookups when processing webhooks.