{"openapi":"3.1.0","info":{"title":"Outstand Social Accounts API v1","description":"# Social Accounts API\n\nThis API enables organizations to manage their connected social media accounts. Social accounts are the actual social media profiles (e.g., @yourcompany) that have been connected to your organization using OAuth credentials configured via the Customer Social Networks API.\n\n## Key Concepts\n\n**Social Accounts** are your actual social media profiles that have been connected and authorized through OAuth flows. These accounts can be used to publish content, schedule posts, and interact with social media platforms through our unified API.\n\n**Social Networks** (configured via the Customer Social Networks API) are the OAuth application credentials required to connect social accounts. One set of social network credentials can be used to connect multiple social accounts on the same platform.\n\n## Supported Platforms\n\nWe support social accounts for: X (Twitter), Threads, LinkedIn, Instagram, Bluesky, YouTube, Facebook, TikTok, Google Business Profile, Pinterest, Vimeo, and Reddit.","version":"1.0.0"},"servers":[{"url":"https://api.outstand.so"}],"components":{},"paths":{"/v1/social-accounts/pending/{sessionToken}":{"get":{"operationId":"getV1SocialAccountsPendingBySessionToken","summary":"Get pending connection details","description":"Retrieve details of a pending OAuth connection, including available pages/accounts that can be connected. This endpoint is used during the OAuth finalization flow for platforms like LinkedIn and Facebook that support multiple pages/profiles.\n\n**Authentication:** Requires your API key, *and* the session token must belong to the same organization as that key. A session token from another organization is rejected as if it had expired. Because the API key is required, call this from your backend - not from the browser your user was redirected to.\n\n**Tokens are never returned.** The response describes each page only well enough to render a picker (`id`, `name`, `profilePictureUrl` and similar). Provider access tokens stay server-side and are attached to the account when you finalize.\n\n**Flow:**\n1. User completes OAuth authentication\n2. Callback redirects to your page with `?session=xxx`\n3. Your backend calls this endpoint to get available pages. Strip the `session` parameter from the browser URL once you have read it - it lands in history, logs and `Referer` headers otherwise\n4. User selects which pages to connect\n5. Call POST /finalize to complete the connection","tags":["Pending Connections"],"responses":{"200":{"description":"Pending connection retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"network":{"type":"string","description":"Social network type","example":"linkedin"},"expiresAt":{"type":"number","description":"Unix timestamp when the session expires","example":1734567890000},"availablePages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the page/account","example":"abc123"},"type":{"type":"string","enum":["personal","organization","page","location"],"description":"Type of account","example":"organization"},"name":{"type":"string","description":"Display name of the account","example":"Acme Inc"},"username":{"type":"string","description":"Username or handle","example":"acme-inc"},"profilePictureUrl":{"type":"string","description":"URL to the profile picture","example":"https://example.com/profile.jpg"},"category":{"type":"string","description":"Facebook Page category","example":"Real Estate Agent"},"urn":{"type":"string","description":"LinkedIn URN for the profile or organization","example":"urn:li:organization:12345"},"accountId":{"type":"string","description":"Google Business Profile account the location belongs to","example":"accounts/1234567890"},"address":{"type":"string","description":"Formatted address of a Google Business Profile location","example":"12 Example St, Sydney NSW 2000"}},"required":["id","type","name","username"],"description":"Available page/account that can be connected. Never includes provider access tokens - the token needed to publish is held server-side and attached when you finalize."}}},"required":["network","expiresAt","availablePages"]}},"required":["success","data"],"description":"Pending connection data with available pages"}}}},"404":{"description":"Session expired or invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Session expired or invalid"}},"required":["success","error"],"description":"Error response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sessionToken","required":true}]}},"/v1/social-accounts/pending/{sessionToken}/finalize":{"post":{"operationId":"postV1SocialAccountsPendingBySessionTokenFinalize","summary":"Finalize pending connection","description":"Complete the OAuth connection by selecting which pages/accounts to connect. This endpoint creates the social account records for the selected pages.\n\n**Authentication:** Requires your API key, *and* the session token must belong to the same organization as that key. A session token from another organization is rejected as if it had expired. Call this from your backend.\n\n**Flow:**\n1. Call GET /pending/:sessionToken to get available pages\n2. User selects which pages to connect\n3. Call this endpoint with the selected page IDs\n4. Social accounts are created and returned\n\n**Note:** The session is automatically deleted after successful finalization.","tags":["Pending Connections"],"responses":{"200":{"description":"Connection finalized successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"connectedAccounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the connected account","example":"9dyJS"},"nickname":{"type":"string","description":"Nickname of the connected account","example":"johndoe"},"username":{"type":"string","description":"Username of the connected account","example":"johndoe"},"network":{"type":"string","description":"Social network type","example":"linkedin"},"accountType":{"type":"string","description":"Type of account","example":"personal"}},"required":["id","nickname","username","network","accountType"],"description":"Successfully connected account"}}},"required":["success","connectedAccounts"],"description":"Response after successfully finalizing connection"}}}},"400":{"description":"Invalid request - missing or invalid parameters","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Session expired or invalid"}},"required":["success","error"],"description":"Error response"}}}},"404":{"description":"Session expired or invalid","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Session expired or invalid"}},"required":["success","error"],"description":"Error response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"selectedPageIds":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Array of page IDs to connect","example":["abc123","org456"]}},"required":["selectedPageIds"],"description":"Request body for finalizing connection"}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sessionToken","required":true}]}},"/v1/social-accounts":{"get":{"operationId":"getV1SocialAccounts","summary":"List connected social accounts","description":"Retrieve all social accounts connected to your organization. This endpoint returns all social media profiles that have been connected and authorized through OAuth flows.\n\n**Use Cases:**\n- View all connected social media accounts for your organization\n- Check which platforms have accounts connected\n- Verify account status and metadata\n- Get account information for use in post creation endpoints\n- Filter accounts by tenant ID, network, username, or unique platform ID\n\n**Filtering:**\n- `id` - Filter by encoded social account ID (exact match)\n- `tenantId` - Filter by tenant ID for multi-tenant applications (exact match)\n- `network` - Filter by social network platform, e.g. `x`, `linkedin`, `instagram` (exact match)\n- `networkUniqueId` - Filter by the account's unique ID on the platform (exact match)\n- `username` - Filter by username or handle (case-insensitive partial match)\n- All filters can be combined for precise queries\n\n**Pagination:**\n- Use `limit` and `offset` query parameters to paginate results\n- Default limit is 50, maximum is 100\n- `total` is the number of accounts matching your filters across all pages; `count` is the number returned in this page\n- Results are always ordered by connection order (oldest connected first), so paging through every offset returns each account exactly once. Accounts connected while you are paginating are appended after the last page rather than shifting the pages you already fetched\n\n**Tokens:** By default, OAuth tokens are never exposed. Pass `includeTokens=true` to include the account's `access_token` nested under a `tokens` object in each result. Only `access_token` is returned - refresh tokens and other sensitive fields remain hidden.","tags":["Social Accounts"],"responses":{"200":{"description":"List of social accounts retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the social account","example":"9dyJS"},"orgId":{"type":"string","description":"Organization ID that owns this social account","example":"org_abc123"},"tenant_id":{"type":["string","null"],"description":"Your own tenant identifier for this account, as supplied when it was connected. Null when the account was connected without one - such an account is not matched by the `tenantId` filter.","example":"tenant_123"},"nickname":{"type":"string","description":"User-friendly nickname for the social account","example":"My Company Twitter"},"network":{"type":"string","description":"Social network platform (e.g., 'x', 'linkedin', 'instagram')","example":"x"},"username":{"type":"string","description":"Username or handle for the social account","example":"@mycompany"},"profile_picture_url":{"type":["string","null"],"description":"URL to the profile picture for the social account","example":"https://example.com/profile.jpg"},"network_unique_id":{"type":"string","description":"Unique identifier for the account on the social network platform","example":"123456789"},"network_webhook_reference_id":{"type":["string","null"],"description":"The id this network uses to identify the account in webhook payloads, when it differs from network_unique_id. Null when the platform uses the same id for both. Used by: Instagram.","example":"17841469709963147"},"customer_social_network_id":{"type":"number","description":"ID of the customer social network configuration used to connect this account","example":5},"accountType":{"type":"string","description":"Type of account: 'personal', 'organization', or 'page'","example":"organization"},"isActive":{"type":["number","null"],"description":"Whether the account is active (1) or inactive (0)","example":1},"createdAt":{"type":["string","null"],"description":"ISO 8601 timestamp when the account was connected","example":"2025-01-15T10:30:00Z"},"tokens":{"type":"object","properties":{"access_token":{"type":["string","null"],"description":"OAuth access token for the account. Only present when the request included includeTokens=true.","example":"ya29.a0Af..."}},"required":["access_token"],"description":"Sensitive OAuth tokens. Only included when includeTokens=true is passed."}},"required":["id","orgId","tenant_id","nickname","network","username","profile_picture_url","network_unique_id","customer_social_network_id","accountType","isActive","createdAt"],"description":"Social account information"}},"count":{"type":"number","description":"Number of social accounts returned in this page","example":3},"total":{"type":"number","description":"Total number of social accounts matching the filters, across all pages","example":292},"limit":{"type":"number","description":"Maximum number of results per page","example":50},"offset":{"type":"number","description":"Number of results to skip","example":0}},"required":["success","data","count","total","limit","offset"],"description":"Successful list operation response"}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Session expired or invalid"}},"required":["success","error"],"description":"Error response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"parameters":[{"in":"query","name":"id","schema":{"type":"string","example":"9dyJS"},"description":"Filter by social account ID (exact match, encoded ID as returned by the API)"},{"in":"query","name":"tenantId","schema":{"type":"string","example":"tenant_123"},"description":"Filter by tenant ID (exact match)"},{"in":"query","name":"network","schema":{"type":"string","example":"x"},"description":"Filter by social network platform (exact match, e.g. 'x', 'linkedin', 'instagram', 'threads', 'bluesky', 'facebook', 'tiktok', 'youtube', 'pinterest', 'vimeo', 'reddit')"},{"in":"query","name":"networkUniqueId","schema":{"type":"string","example":"123456789"},"description":"Filter by the account's unique identifier on the social network platform (exact match)"},{"in":"query","name":"username","schema":{"type":"string","example":"mycompany"},"description":"Filter by username or handle (case-insensitive partial match)"},{"in":"query","name":"limit","schema":{"type":"number","minimum":1,"maximum":100,"default":50,"example":50},"description":"Maximum number of results to return (1-100)"},{"in":"query","name":"offset","schema":{"type":"number","minimum":0,"default":0,"example":0},"description":"Number of results to skip for pagination"},{"in":"query","name":"includeTokens","schema":{"type":"string","enum":["true","false"],"example":"false"},"description":"When true, include the account's access_token (from network_data) under a `tokens` object in each result. Defaults to false; tokens are never returned otherwise."}]}},"/v1/social-accounts/{id}":{"delete":{"operationId":"deleteV1SocialAccountsById","summary":"Delete a social account","description":"**WARNING: This is an irrevocable action.**\n\nPermanently deletes a social account and revokes all access. This action:\n\n- **Cannot be undone** - the social account connection is permanently removed\n- **Revokes access entirely** - OAuth tokens are deleted and platform access is terminated\n- **Deletes all social account data immediately** - profile information, tokens, and metadata are removed from our system\n- **Posts cleanup** - Posts made from this account will eventually be cleaned up from our system (the posts remain on the social platform)\n\nTo reconnect this account, you will need to complete the full OAuth flow again.","tags":["Social Accounts"],"responses":{"200":{"description":"Social account deleted successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Social account deleted successfully"}},"required":["success","message"],"description":"Successful deletion response"}}}},"404":{"description":"Social account not found or not owned by organization","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Social account not found"}},"required":["success","error"],"description":"Resource not found response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}]}},"/v1/social-accounts/bluesky":{"post":{"operationId":"postV1SocialAccountsBluesky","summary":"Connect a Bluesky account","description":"Connect a Bluesky account using handle and app password authentication. Bluesky uses app passwords instead of OAuth, so credentials are provided directly.\n\n**Prerequisites:**\n1. Configure Bluesky in your social networks: `POST /v1/social-networks` with `network: \"bluesky\"`\n2. Create an app password at https://bsky.app/settings/app-passwords\n\n**Reconnecting:** if the handle is already connected for the same `tenantId`, the existing account is replaced (credentials and profile refreshed) instead of duplicated. Connecting the same handle under a different `tenantId` creates a separate account.\n\n**Security Note:** App passwords are scoped credentials that don't grant access to your main password. They can be revoked at any time from Bluesky settings.","tags":["Social Accounts"],"responses":{"201":{"description":"Bluesky account connected successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the social account","example":"9dyJS"},"orgId":{"type":"string","description":"Organization ID that owns this social account","example":"org_abc123"},"tenant_id":{"type":["string","null"],"description":"Your own tenant identifier for this account, as supplied when it was connected. Null when the account was connected without one - such an account is not matched by the `tenantId` filter.","example":"tenant_123"},"nickname":{"type":"string","description":"User-friendly nickname for the social account","example":"My Company Twitter"},"network":{"type":"string","description":"Social network platform (e.g., 'x', 'linkedin', 'instagram')","example":"x"},"username":{"type":"string","description":"Username or handle for the social account","example":"@mycompany"},"profile_picture_url":{"type":["string","null"],"description":"URL to the profile picture for the social account","example":"https://example.com/profile.jpg"},"network_unique_id":{"type":"string","description":"Unique identifier for the account on the social network platform","example":"123456789"},"network_webhook_reference_id":{"type":["string","null"],"description":"The id this network uses to identify the account in webhook payloads, when it differs from network_unique_id. Null when the platform uses the same id for both. Used by: Instagram.","example":"17841469709963147"},"customer_social_network_id":{"type":"number","description":"ID of the customer social network configuration used to connect this account","example":5},"accountType":{"type":"string","description":"Type of account: 'personal', 'organization', or 'page'","example":"organization"},"isActive":{"type":["number","null"],"description":"Whether the account is active (1) or inactive (0)","example":1},"createdAt":{"type":["string","null"],"description":"ISO 8601 timestamp when the account was connected","example":"2025-01-15T10:30:00Z"},"tokens":{"type":"object","properties":{"access_token":{"type":["string","null"],"description":"OAuth access token for the account. Only present when the request included includeTokens=true.","example":"ya29.a0Af..."}},"required":["access_token"],"description":"Sensitive OAuth tokens. Only included when includeTokens=true is passed."}},"required":["id","orgId","tenant_id","nickname","network","username","profile_picture_url","network_unique_id","customer_social_network_id","accountType","isActive","createdAt"],"description":"Social account information"}},"required":["success","data"],"description":"Successful Bluesky account creation response"}}}},"400":{"description":"Invalid credentials or missing fields","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Session expired or invalid"}},"required":["success","error"],"description":"Error response"}}}},"409":{"description":"Account already connected","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Account already connected"}},"required":["success","error"],"description":"Conflict error response when account already exists"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"handle":{"type":"string","minLength":1,"description":"Bluesky handle (e.g., user.bsky.social)","example":"user.bsky.social"},"appPassword":{"type":"string","minLength":1,"description":"Bluesky app password (from bsky.app/settings/app-passwords)","example":"xxxx-xxxx-xxxx-xxxx"},"tenantId":{"type":"string","description":"Optional tenant ID to associate with this account","example":"tenant_123"}},"required":["handle","appPassword"],"description":"Request body for creating a Bluesky social account"}}}}}},"/v1/social-accounts/{id}/metrics":{"get":{"operationId":"getV1SocialAccountsByIdMetrics","summary":"Get account metrics","description":"Fetch analytics and metrics for a connected social account. Returns follower counts, engagement metrics, and platform-specific statistics.\n\n**Supported Metrics by Platform:**\n- **Instagram:** followers, following, media count, engagement (views, likes, comments, shares, saves, reach, accounts_engaged, total_interactions), and `follower_growth` (followers_gained, followers_lost, net_follower_change, daily_new_followers) - requires Business/Creator account with `instagram_business_manage_insights` permission (supports date range). Instagram omits follower growth for accounts with fewer than 100 followers; those fields are null and listed in `follower_growth.unavailable_fields`\n- **Facebook:** page followers/fans, engagement (impressions, reach, post_engagements) - requires `pages_read_engagement` and `read_insights`, supports date range. Since Meta's June 2026 deprecation, impressions and reach are derived from media views and read lower than the retired impression metrics; metrics Meta did not return are listed in `platform_specific.insights_unavailable`\n- **Threads:** followers, engagement (views, likes, replies, reposts, quotes) - supports date range\n- **LinkedIn:** followers (personal & organization), engagement for organizations (likes, comments, shares, clicks, impressions, engagement_rate) - requires `rw_organization_admin` permission, supports date range\n- **TikTok:** followers, following, total likes, video count - current snapshot only, no date range support\n- **YouTube:** subscribers, total views, video count - lifetime statistics only, no date range support\n- **X (Twitter):** followers, following, tweet count (current snapshot), plus engagement (views, likes, comments, shares, quotes) aggregated from up to 500 of the account's own tweets posted within the date range. Aggregation is best-effort and may be unavailable under X API rate limits or tier restrictions. **Cost note:** this reads posts from your connected X app and counts against your X API quota / pay-per-use cost (~$0.005 per post read); a busy account can cost up to ~$2.50 per call. Date range supported.\n- **BlueSky:** followers, following, posts count - current snapshot only (Bluesky exposes no time-series analytics, so the date range is ignored). No engagement metrics.\n- **Pinterest:** followers, following, pin count (`posts_count` includes both created and saved pins, per Pinterest's API), engagement (views/impressions, saves, pin_clicks, outbound_clicks); full daily analytics available under `platform_specific`. Date range supported.\n\n**Date Range:** Use `since` and `until` query parameters for platforms that support historical data. Defaults to last 30 days.","tags":["Social Accounts"],"responses":{"200":{"description":"Account metrics retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"account_id":{"type":"string","example":"9dyJS"},"network":{"type":"string","example":"tiktok"},"followers_count":{"type":["number","null"],"example":10000},"following_count":{"type":["number","null"],"example":500},"posts_count":{"type":["number","null"],"example":150},"engagement":{"type":["object","null"],"properties":{"views":{"type":["number","null"],"example":15000},"likes":{"type":["number","null"],"example":500},"comments":{"type":["number","null"],"example":75},"shares":{"type":["number","null"],"example":25},"saves":{"type":["number","null"],"example":10},"reposts":{"type":["number","null"],"example":10},"quotes":{"type":["number","null"],"example":5},"reach":{"type":["number","null"],"example":5000},"accounts_engaged":{"type":["number","null"],"example":200},"total_interactions":{"type":["number","null"],"example":600},"replies":{"type":["number","null"],"example":12,"description":"Instagram: account-level story replies"},"profile_links_taps":{"type":["number","null"],"example":30}},"additionalProperties":true,"description":"Engagement metrics for the date range. Fields vary by platform."},"stories":{"type":["object","null"],"properties":{"views":{"type":["number","null"]},"reach":{"type":["number","null"]},"total_interactions":{"type":["number","null"]},"replies":{"type":["number","null"]}},"description":"Instagram: engagement attributable to Stories over the date range (media_product_type=STORY breakdown)"},"follower_growth":{"type":["object","null"],"properties":{"followers_gained":{"type":["number","null"],"example":42,"description":"Accounts that followed during the date range"},"followers_lost":{"type":["number","null"],"example":9,"description":"Accounts that unfollowed during the date range"},"net_follower_change":{"type":["number","null"],"example":33,"description":"followers_gained minus followers_lost"},"daily_new_followers":{"type":["array","null"],"items":{"type":"object","properties":{"end_time":{"type":"string","example":"2026-10-01T07:00:00+0000"},"value":{"type":"number","example":3}},"required":["end_time","value"]},"description":"New followers per day over the date range (Instagram follower_count, period=day)"},"unavailable_fields":{"type":"array","items":{"type":"string"},"example":[],"description":"Fields Instagram did not report and that are therefore null"}},"required":["followers_gained","followers_lost","net_follower_change","daily_new_followers","unavailable_fields"],"description":"Instagram: follower growth over the date range. Instagram does not report it for accounts with fewer than 100 followers; those fields are null and named in unavailable_fields. Data can lag up to 48 hours."},"platform_specific":{"type":"object","additionalProperties":{},"description":"Raw platform-specific data from the API"},"period":{"type":"object","properties":{"since":{"type":"number","example":1704067200},"until":{"type":"number","example":1706745600},"note":{"type":"string","example":"This platform returns current snapshot, not historical data"}},"required":["since","until"],"description":"Date range for the metrics"},"fetched_at":{"type":"string","example":"2025-01-15T10:30:00Z"}},"required":["account_id","network","followers_count","following_count","posts_count","engagement","platform_specific","period","fetched_at"],"description":"Account metrics data"}},"required":["success","data"],"description":"Account metrics response"}}}},"400":{"description":"Validation Error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"array","items":{}},"data":{}},"required":["success","error","data"]}}}},"404":{"description":"Social account not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Social account not found"}},"required":["success","error"],"description":"Resource not found response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"parameters":[{"in":"query","name":"since","schema":{"type":"number","example":1704067200},"description":"Unix timestamp for start of date range (defaults to 30 days ago)"},{"in":"query","name":"until","schema":{"type":"number","example":1706745600},"description":"Unix timestamp for end of date range (defaults to now)"},{"schema":{"type":"string"},"in":"path","name":"id","required":true}]}},"/v1/social-accounts/{id}/health":{"get":{"operationId":"getV1SocialAccountsByIdHealth","summary":"Check account health","description":"Checks whether the stored access token for a social account is still valid by calling the network's identity endpoint.\n\nIf the token is expired (401), one automatic refresh is attempted and the new tokens are persisted before re-checking.\n\n**Supported networks:** X, LinkedIn, Facebook, Instagram, Threads, TikTok, YouTube, Pinterest, Bluesky, Google Business, Vimeo, Reddit","tags":["Social Accounts"],"responses":{"200":{"description":"Health check result (may be healthy: false)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"id":{"type":"string","description":"Social account ID","example":"9dyJS"},"network":{"type":"string","description":"Social network name","example":"instagram"},"healthy":{"type":"boolean","description":"Whether the stored token is currently valid","example":true},"checkedAt":{"type":"string","description":"ISO timestamp of the check","example":"2024-01-01T00:00:00.000Z"},"details":{"type":"object","additionalProperties":{},"description":"Identity details from the network (e.g. username, id)"},"error":{"type":"string","description":"Error message when unhealthy"},"errorCode":{"type":"string","enum":["unauthorized","forbidden","rate_limited","network_error","unknown"],"description":"Machine-readable error code when unhealthy"}},"required":["id","network","healthy","checkedAt"],"description":"Health status of the social account"}},"required":["success","data"],"description":"Account health response"}}}},"404":{"description":"Social account not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Social account not found"}},"required":["success","error"],"description":"Resource not found response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}]}},"/v1/social-accounts/{id}/imports":{"post":{"operationId":"postV1SocialAccountsByIdImports","summary":"Import posts from a social account","description":"Enqueues an import job to fetch and store existing posts from the connected social account platform. The job runs asynchronously - poll the returned import ID or listen for an `import.completed` / `import.failed` webhook event.\n\n**Supported networks:** Bluesky, LinkedIn, Facebook, Instagram, Threads, TikTok, YouTube, Pinterest, Google Business\n\n**Note:** LinkedIn post imports are only supported for business (organization) accounts - personal LinkedIn accounts cannot import posts.\n\n**Unsupported:** X (Twitter) - API tier restrictions prevent user timeline access.\n\n**Billing:** Each successfully imported post counts as one `social_posts` usage unit, billed the same day the import runs.","tags":["Social Accounts"],"responses":{"202":{"description":"Import job created and queued","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"id":{"type":"string"},"orgId":{"type":"string"},"socialAccountId":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed","partial"]},"since":{"type":["string","null"]},"until":{"type":["string","null"]},"limit":{"type":["number","null"]},"imported":{"type":"number"},"skipped":{"type":"number"},"failed":{"type":"number"},"error":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"completedAt":{"type":["string","null"]}},"required":["id","orgId","socialAccountId","status","since","until","limit","imported","skipped","failed","error","createdAt","updatedAt","completedAt"],"description":"Import job status"}},"required":["success","data"]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Session expired or invalid"}},"required":["success","error"],"description":"Error response"}}}},"404":{"description":"Social account not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Social account not found"}},"required":["success","error"],"description":"Resource not found response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"since":{"type":"string","format":"date-time","description":"Import posts published after this ISO 8601 timestamp","example":"2024-01-01T00:00:00Z"},"until":{"type":"string","format":"date-time","description":"Import posts published before this ISO 8601 timestamp","example":"2025-01-01T00:00:00Z"},"limit":{"type":"integer","exclusiveMinimum":0,"maximum":1000,"description":"Maximum number of posts to import","example":100}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}]},"get":{"operationId":"getV1SocialAccountsByIdImports","summary":"List import jobs for a social account","description":"Returns all import jobs for the specified social account, ordered by most recent first.","tags":["Social Accounts"],"responses":{"200":{"description":"Import jobs retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"orgId":{"type":"string"},"socialAccountId":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed","partial"]},"since":{"type":["string","null"]},"until":{"type":["string","null"]},"limit":{"type":["number","null"]},"imported":{"type":"number"},"skipped":{"type":"number"},"failed":{"type":"number"},"error":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"completedAt":{"type":["string","null"]}},"required":["id","orgId","socialAccountId","status","since","until","limit","imported","skipped","failed","error","createdAt","updatedAt","completedAt"],"description":"Import job status"}},"count":{"type":"number"}},"required":["success","data","count"]}}}},"404":{"description":"Social account not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Social account not found"}},"required":["success","error"],"description":"Resource not found response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}]}},"/v1/social-accounts/{id}/imports/{importId}":{"get":{"operationId":"getV1SocialAccountsByIdImportsByImportId","summary":"Get import job status","description":"Returns the current status and progress of an import job.","tags":["Social Accounts"],"responses":{"200":{"description":"Import job retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"id":{"type":"string"},"orgId":{"type":"string"},"socialAccountId":{"type":"string"},"status":{"type":"string","enum":["queued","running","completed","failed","partial"]},"since":{"type":["string","null"]},"until":{"type":["string","null"]},"limit":{"type":["number","null"]},"imported":{"type":"number"},"skipped":{"type":"number"},"failed":{"type":"number"},"error":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"completedAt":{"type":["string","null"]}},"required":["id","orgId","socialAccountId","status","since","until","limit","imported","skipped","failed","error","createdAt","updatedAt","completedAt"],"description":"Import job status"}},"required":["success","data"]}}}},"404":{"description":"Import job not found","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Social account not found"}},"required":["success","error"],"description":"Resource not found response"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","example":"Internal server error"},"message":{"type":"string","example":"Database connection failed"}},"required":["success","error"],"description":"Internal server error response"}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true},{"schema":{"type":"string"},"in":"path","name":"importId","required":true}]}}}}