{ "openapi": "3.0.3", "info": { "title": "VoxBurst API", "version": "1.0.0", "description": "\n# VoxBurst API\n\nVoxBurst is a social media scheduling and publishing API. Publish to Twitter/X, LinkedIn, Facebook, Instagram, Bluesky, and more from a single API.\n\n## Getting Started\n\n### Base URL\n```\nhttps://api.voxburst.io/v1\n```\n\n### Authentication\n\nAll API endpoints require authentication via one of:\n\n1. **Cognito JWT Token** - For user-authenticated requests from the web app\n2. **API Key** - For programmatic access (starts with `vb_live_` or `vb_test_`)\n\nInclude the token in the Authorization header:\n```\nAuthorization: Bearer \n```\n\n### Quick Start\n\n```bash\n# 1. Create a post\ncurl -X POST https://api.voxburst.io/v1/posts \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"content\":\"Hello World\",\"accountIds\":[\"cmmmdwv6e0002yvot7ph96591\"]}'\n\n# 2. Publish with sync mode (wait for completion)\ncurl -X POST \"https://api.voxburst.io/v1/posts/123/publish?sync=true&timeout=60\" \\\n -H \"Authorization: Bearer $TOKEN\"\n\n# 3. Check status\ncurl https://api.voxburst.io/v1/posts/123 \\\n -H \"Authorization: Bearer $TOKEN\"\n```\n\n## What VoxBurst Does & Doesn't Do\n\nVoxBurst is a **publishing and inbox management** API — not a full social engagement platform.\n\n### ✅ What VoxBurst Supports\n- **Publishing**: Create, schedule, and publish posts to 15+ social platforms\n- **Inbox Management**: Read incoming comments and reply to them\n- **Analytics**: View performance metrics, engagement stats, and follower counts\n- **First Comments**: Auto-post a first comment with your content (hashtags, links, etc.)\n- **Media Management**: Upload and manage images/videos for posts\n\n### ❌ What VoxBurst Does NOT Support\n- Liking or favoriting posts\n- Reposting, retweeting, or sharing content\n- Following or unfollowing accounts\n- Direct messaging (DMs)\n- Any other social interactions beyond publishing and comment replies\n\nIf you need full social engagement automation, VoxBurst is not the right tool. If you need publishing + inbox management (a social media inbox), VoxBurst is designed for exactly that.\n\n## Rate Limiting\n\nAPI requests are rate-limited based on your plan tier:\n\n| Plan | Requests/minute | Burst limit |\n|------|-----------------|-------------|\n| Free | 120 | 10/sec |\n| Starter | 200 | 15/sec |\n| Pro | 500 | 20/sec |\n| Agency | 1000 | 50/sec |\n\nRate limit headers are included in all responses:\n- `X-RateLimit-Limit`: Maximum requests per window\n- `X-RateLimit-Remaining`: Requests remaining\n- `X-RateLimit-Reset`: Unix timestamp when the window resets\n\n**HTTP 429** is returned when limits are exceeded. Retry after the time specified in `Retry-After` header.\n\n## Idempotency\n\nFor safe retries on mutations, include an `Idempotency-Key` header:\n```\nIdempotency-Key: \n```\n\nKeys are stored for 24 hours. Duplicate requests return the original response.\n\n## Pagination\n\nList endpoints use cursor-based pagination:\n- `limit`: Number of items per page (default: 20, max: 100)\n- `cursor`: Opaque cursor from previous response\n\nResponse includes:\n- `data`: Array of items\n- `nextCursor`: Cursor for next page (null if no more pages)\n- `hasMore`: Boolean indicating if more pages exist\n\n## Error Response Format\n\nAll errors follow a consistent format:\n\n```json\n{\n \"error\": {\n \"code\": \"VALIDATION_ERROR\",\n \"message\": \"Human-readable description\",\n \"details\": { \"field\": \"specific error info\" },\n \"docs_url\": \"https://docs.voxburst.io/errors/validation\"\n }\n}\n```\n\n### Common Error Codes\n\n| Code | Description | Resolution |\n|------|-------------|------------|\n| `VALIDATION_ERROR` | Invalid request parameters | Check `details` for field-specific errors |\n| `UNAUTHORIZED` | Missing or invalid token | Verify Authorization header |\n| `FORBIDDEN` | Insufficient permissions | Check workspace membership and roles |\n| `NOT_FOUND` | Resource does not exist | Verify ID in URL |\n| `RATE_LIMIT_EXCEEDED` | API rate limit hit | Wait and retry per headers |\n| `NO_PAGE_SELECTED` | Facebook page not chosen | Call POST /v1/accounts/{id}/select-page |\n| `MEDIA_NOT_READY` | Upload not complete | Wait for media processing to finish |\n| `CONTAINER_FAILED` | Instagram/Threads container error | Retry with different media |\n| `CONTAINER_TIMEOUT` | Container processing timeout | Retry the publish operation |\n| `NO_IG_ACCOUNT` | Instagram account ID missing | Reconnect Instagram account |\n| `PLATFORM_RATE_LIMIT` | Platform-specific rate limit | Wait before retrying |\n\n## Platform-Specific Quirks\n\nVoxBurst supports 15 social media platforms. Each has unique content rules enforced at validation time.\nUse `POST /v1/posts/validate` to check content against all platform limits before publishing.\n\n### Quick Reference Table\n\n| Platform | Chars | Images | Videos | Hashtags | Links | First Comment |\n|---|---|---|---|---|---|---|\n| Twitter/X | 280 | 4 × 5MB | 1 × 512MB (2:20) | 1–3 rec. | ✅ (count as 23 chars) | ❌ |\n| LinkedIn | 3,000 | 9 × 8MB | 1 × 5GB (10 min) | 3–5 rec. | ✅ | ✅ |\n| Instagram | 2,200 | 10 × 8MB JPEG | 10 × 100MB (60s) | max 30 | ❌ (bio only) | ✅ |\n| Facebook | 63,206 | 10 × 30MB | 1 × 4GB (4 hrs) | 0–3 rec. | ✅ | ✅ |\n| Threads | 500 | 10 × 8MB | 1 × 100MB (5 min) | 1–5 rec. | ✅ | ✅ |\n| Bluesky | 300 | 4 × 1MB | ❌ none yet | 1–3 rec. | ✅ | ❌ |\n| TikTok | 2,200 | 35 × 20MB | 1 × 287MB (10 min) | 3–5 rec. | ❌ | ✅ |\n| YouTube | 5,000 | thumbnails only | 1 × 256GB (12 hrs) | max 15 | ✅ | ✅ |\n| Pinterest | 500 | 5 × 32MB | 1 × 2GB (15 min) | 2–5 rec. | ✅ (dest. URL) | ❌ |\n| Reddit | 40,000 | 20 × 20MB | 1 × 1GB (15 min) | ❌ none | ✅ | ✅ |\n| Snapchat | 80 | 1 × 5MB | 1 × 100MB (60s) | ❌ none | ✅ (swipe-up) | ❌ |\n| Telegram | 4,096 | 10 × 10MB | 1 × 2GB (1 hr) | 0–5 rec. | ✅ | ❌ |\n| Google Business | 1,500 | 10 × 25MB | 1 × 100MB (30s) | ❌ none | ✅ (CTA) | ❌ |\n| Mastodon | 500* | 4 × 16MB | 1 × 100MB (5 min) | 1–5 rec. | ✅ | ❌ |\n| WhatsApp | 4,096 | 30 × 16MB | 1 × 16MB (3 min) | n/a | ✅ | ❌ |\n\n---\n\n### Twitter/X\n- **Character limit**: 280 characters — URLs always count as exactly 23 characters regardless of length\n- **Images**: Up to 4 images (max 5MB each); formats: JPEG, PNG, GIF, WebP\n- **Video**: 1 video (max 512MB, max 2 min 20 sec); formats: MP4, MOV\n- **GIF**: 1 animated GIF (max 15MB)\n- **Media rules**: Cannot mix images and video in the same post\n- **Hashtags**: No hard limit; 1–3 recommended for best engagement\n- **Links**: Clickable, link previews supported; all URLs shortened to t.co (23 chars)\n- **First comment**: Not supported\n- **Rate limits**: 300 tweets per 3 hours (user context); 300 per day (basic tier)\n- **Best practices**: Keep under 200 chars for replies; use 1-3 hashtags max; threads extend reach\n\n### LinkedIn\n- **Character limit**: 3,000 characters for posts; articles support up to 125,000\n- **Images**: Up to 9 images (max 8MB each); formats: JPEG, PNG, GIF\n- **Video**: 1 video (max 5GB, max 10 minutes); formats: MP4, MOV, AVI\n- **PDF documents**: Supported as native document posts\n- **Media rules**: Cannot mix images and video in the same post\n- **Hashtags**: Soft limit of 30; 3–5 hashtags optimal for reach (more is flagged as spam)\n- **Mentions**: Up to 100 mentions per post\n- **Links**: Clickable, link previews supported\n- **First comment**: Supported — great for adding hashtags without cluttering post\n- **Organization posting**: Use `organization` param to post as a company page\n- **Rate limits**: ~150 posts per day\n- **Best practices**: Post longer content for thought-leadership; 3-5 hashtags in first comment\n\n### Instagram\n- **Character limit**: 2,200 characters; first 125 chars visible before \"More\"\n- **Images**: Up to 10 images (max 8MB each); **JPEG only via API — PNG not supported**\n- **Video**: Up to 10 videos (max 100MB, max 60 sec for feed); formats: MP4, MOV\n- **Aspect ratios**: 1.91:1 (landscape) to 4:5 (portrait); square 1:1 also optimal\n- **Carousels**: Up to 10 slides; can mix images and video\n- **Hashtags**: Hard limit of 30; 5–15 recommended; consider putting hashtags in first comment\n- **Mentions**: Up to 20 mentions per post\n- **Links**: **NOT clickable in captions** — use \"Link in Bio\" strategy\n- **First comment**: Supported with optional delay; ideal for hashtag placement\n- **Publishing flow**: Container-based (async) — media uploaded → container created → published\n- **Rate limits**: 100 API-published posts per 24 hours; containers expire after 24 hours\n- **Best practices**: JPEG-only for API uploads; vertical 4:5 gets more feed real estate\n\n### Facebook\n- **Character limit**: 63,206 characters; first ~477 chars visible before \"See More\"\n- **Images**: Up to 10 images (max 30MB each); formats: JPEG, PNG, GIF, WebP\n- **Video**: 1 video (max 4GB, max 4 hours); formats: MP4, MOV, AVI\n- **GIF**: 1 animated GIF supported\n- **Hashtags**: No hard limit; hashtags are less effective on Facebook; 0–3 recommended\n- **Links**: Clickable, link previews supported\n- **First comment**: Supported\n- **Page selection**: Must call `POST /v1/accounts/{id}/select-page` after OAuth for multi-page accounts\n- **Business Accounts**: Require `business_management` permission\n- **Rate limits**: ~60 posts per hour per Page\n- **Best practices**: Front-load key content in first 477 chars; use video for highest reach\n\n### Threads\n- **Character limit**: 500 characters\n- **Images**: Up to 10 images (max 8MB each); formats: JPEG, PNG, GIF, WebP\n- **Video**: 1 video (max 100MB, max 5 minutes); formats: MP4, MOV\n- **Carousels**: Supported; can mix images and video\n- **Hashtags**: No hard limit; 1–5 recommended\n- **Links**: Clickable, link previews supported\n- **First comment**: Supported\n- **Publishing flow**: Container-based (similar to Instagram) — 30 second processing timeout\n- **Best practices**: Conversational tone; thread chains extend engagement\n\n### Bluesky\n- **Character limit**: 300 characters\n- **Images**: Up to 4 images (max 1MB each — strict limit); formats: JPEG, PNG, GIF, WebP\n- **Video**: Not yet supported\n- **GIF**: 1 animated GIF supported\n- **Hashtags**: No hard limit; 1–3 recommended\n- **Links**: Clickable, link previews (card embeds) supported\n- **First comment**: Not supported\n- **Protocol**: AT Protocol — uses decentralized identity (DIDs and handles)\n- **Scheduling**: Not natively supported; VoxBurst handles delayed dispatch\n- **Best practices**: Image size limit is strict at 1MB — compress images before uploading\n\n### TikTok\n- **Character limit**: 2,200 characters for captions\n- **Images**: Up to 35 images in Photo Mode (max 20MB each); formats: JPEG, PNG, WebP\n- **Video**: 1 video (max 287MB via web upload, max 10 minutes); formats: MP4, MOV, WebM\n- **Aspect ratios**: 9:16 vertical strongly recommended; horizontal (16:9) also supported\n- **Media rules**: Photo Mode and Video Mode are separate; cannot mix\n- **Hashtags**: Hard limit of 100; **3–5 trending hashtags recommended** — do not spam\n- **Links**: **NOT clickable in captions** — only clickable in bio; swipe-up for ads\n- **First comment**: Supported — good place for additional tags and links\n- **Rate limits**: ~20 posts per day via API; video processing can take several minutes\n- **Best practices**: Video-first platform; use trending sounds; hook viewers in first 3 seconds\n\n### YouTube\n- **Character limit**: 5,000 characters for description; 100 chars for title\n- **Images**: Thumbnails only (not a direct post image); formats: JPEG, PNG, GIF, BMP\n- **Video**: 1 video (max 256GB, max 12 hours); formats: MP4, MOV, AVI, WMV, FLV, WebM\n- **Aspect ratios**: 16:9 recommended; 4:3 also supported\n- **Hashtags**: Hard limit of 15; **first 3 hashtags appear above the video title**; 3–5 recommended\n- **Links**: Clickable in descriptions and as cards/end screens\n- **First comment**: Supported — can be pinned by creator\n- **Rate limits**: ~10 video uploads per day (unverified accounts); 100/day (verified)\n- **Best practices**: Front-load keywords in first 100 chars of description; chapters via timestamps; first 3 hashtags are most visible\n\n### Pinterest\n- **Character limit**: 500 characters for pin description\n- **Images**: Up to 5 images (max 32MB each); formats: JPEG, PNG, GIF, WebP\n- **Video**: 1 video (max 2GB, max 15 minutes); formats: MP4, MOV, M4V\n- **Aspect ratios**: **2:3 vertical performs best** (1000×1500px ideal); 1:1 square also good; avoid landscape\n- **Carousels**: Up to 5 images; can mix\n- **Hashtags**: Up to 20; 2–5 relevant hashtags recommended\n- **Links**: **Destination URL is critical** — Pinterest is a discovery-to-purchase platform; clicks go to your site\n- **First comment**: Not supported\n- **Rate limits**: ~100 pins per day\n- **Best practices**: Vertical 2:3 images consistently outperform; include destination URL; descriptive text with keywords improves search discoverability\n\n### Reddit\n- **Character limit**: 40,000 characters (self/text posts)\n- **Images**: Up to 20 images in gallery posts (max 20MB each); formats: JPEG, PNG, GIF, WebP\n- **Video**: 1 video (max 1GB, max 15 minutes); formats: MP4, MOV\n- **Media rules**: Cannot mix images and video in gallery\n- **Hashtags**: **Reddit does NOT use hashtags** — do not include them; they appear as plain text\n- **Links**: Clickable, link previews supported; link posts vs. text posts are different types\n- **First comment**: Supported — common pattern for OP to add context in first comment\n- **Rate limits**: Subreddit-specific limits; typically 1–10 posts per hour; karma requirements vary\n- **Best practices**: Read subreddit rules carefully — rules vary wildly; no hashtags; participate in the community before self-promoting\n\n### Snapchat\n- **Character limit**: **80 characters only** — very short; plan content accordingly\n- **Images**: 1 image (max 5MB); formats: JPEG, PNG, WebP\n- **Video**: 1 video (max 100MB, max 60 seconds); formats: MP4, MOV\n- **Aspect ratios**: **9:16 vertical is required** — horizontal content will be rejected\n- **Hashtags**: Not supported on Snapchat\n- **Links**: Supported via swipe-up (for Spotlight/Ads) — not standard link embeds\n- **First comment**: Not supported\n- **Rate limits**: Varies by account type; ~10 Stories/day typical\n- **Best practices**: Vertical 9:16 full-screen content only; keep caption under 80 chars; ephemeral content mindset\n\n### Telegram\n- **Character limit**: 4,096 characters for messages (1,024 for media captions — note the difference)\n- **Images**: Up to 10 images in an album (max 10MB each); formats: JPEG, PNG, GIF, WebP\n- **Video**: 1 video (max 2GB, max 1 hour); formats: MP4, MOV, MKV\n- **GIF**: Supported (converted to Telegram's animation format)\n- **Carousels**: Supported via media groups (album); can mix images and video\n- **Hashtags**: No platform enforcement; 0–5 recommended for channel discoverability\n- **Links**: Clickable, inline previews supported; supports inline buttons via Bot API\n- **Formatting**: **Supports rich text** — bold (`**text**`), italic (`_text_`), code blocks, spoilers\n- **First comment**: Not natively supported\n- **Rate limits**: Bot API: 30 messages/second globally; 20 messages/minute per chat\n- **Best practices**: Use formatting to improve readability; media groups deliver cleaner UX than individual files\n\n### Google Business Profile\n- **Character limit**: 1,500 characters for post body; 58 chars for event titles\n- **Images**: Up to 10 images (max 25MB each, min 250px × 250px); formats: JPEG, PNG\n- **Video**: 1 video (max 100MB, max 30 seconds); formats: MP4\n- **Hashtags**: Not supported and not recommended — Google does not use hashtags for GMB\n- **Links**: **CTA (Call-to-Action) buttons supported** — Learn More, Buy, Sign Up, Call\n- **Post types**: What's New, Event, Offer, Product (each has unique required fields)\n- **First comment**: Not supported (not applicable)\n- **Rate limits**: ~5 posts per day per location\n- **Best practices**: Include clear CTA button; use local keywords; post regularly for local SEO boost; images must meet minimum size requirements\n\n### Mastodon\n- **Character limit**: **500 characters default** — varies by instance (500–5,000 chars depending on server config)\n- **Images**: Up to 4 images (max 16MB each — server default, may vary); formats: JPEG, PNG, GIF, WebP\n- **Video**: 1 video (max 100MB, max 5 minutes — server default); formats: MP4, MOV, WebM\n- **GIF**: Supported\n- **Hashtags**: No hard limit; **1–5 recommended**; **use CamelCase for accessibility** (e.g., `#SocialMedia` not `#socialmedia`)\n- **Links**: Clickable, link previews (Open Graph cards) supported\n- **Content Warnings**: Supported — CW text appears instead of post until user clicks\n- **First comment**: Not supported natively\n- **Federated network**: Posts go to your instance and federate to followers across the Fediverse\n- **Rate limits**: Typically 300 posts per 5 minutes (instance-configurable)\n- **Best practices**: CamelCase hashtags improve screen-reader accessibility; content warnings for sensitive topics; check instance-specific character limits\n\n### WhatsApp Business\n- **Character limit**: 4,096 characters for messages/status; 1,024 for media captions\n- **Images**: Up to 30 images in broadcast (max 16MB each); formats: JPEG, PNG\n- **Video**: 1 video (max 16MB, max 3 minutes) for Status; formats: MP4, MOV, AVI\n- **GIF**: Supported\n- **Carousels**: Supported (interactive message templates)\n- **Hashtags**: No hashtag functionality on WhatsApp\n- **Links**: Clickable, link previews supported in chats\n- **First comment**: Not applicable\n- **24-Hour Window**: **Critical policy** — can only send free-form messages within 24 hours of user's last message; outside window requires approved message templates\n- **Opt-in required**: Users must explicitly opt in to receive messages — violating this risks account ban\n- **Rate limits**: Depends on business tier; typically 1,000–100,000 messages/day\n- **Best practices**: Always respect the 24-hour messaging window; use approved templates for outbound campaigns; obtain explicit opt-in before messaging\n\n## Best Practices\n\n### Publishing Strategies\n\n1. **Use sync mode for immediate feedback**\n ```\n POST /v1/posts/{id}/publish?sync=true\n ```\n\n2. **Use webhooks for production workloads**\n ```\n X-Callback-Url: https://yourapp.com/webhooks/voxburst\n ```\n\n3. **Poll for status if not using sync or webhooks**\n ```\n GET /v1/posts/{id} # Poll every 2-5 seconds\n ```\n\n4. **Handle PARTIAL status**\n - Some platforms succeed, others fail\n - Check `platformStatus` array for per-platform details\n - Retry with `POST /v1/posts/{id}/retry`\n\n5. **Verify before publishing**\n - Use `POST /v1/posts/validate` to check content against platform limits\n - Check media status with `GET /v1/media/{id}` before publishing\n\n### Error Handling\n\n- Always check for `PARTIAL` status after publishing\n- Inspect `platformStatus` array for per-platform error details\n- Retry only `retryable: true` errors\n- Use idempotency keys for safe retries\n\n### Media Handling\n\n- Upload media before creating posts\n- Wait for `status: READY` before publishing\n- Instagram requires JPEG format\n- Respect platform size limits (check `GET /v1/platforms/capabilities`)\n ", "contact": { "name": "VoxBurst Support", "email": "voxburst@fortheanlabs.com", "url": "https://docs.voxburst.io" }, "license": { "name": "Proprietary" } }, "servers": [ { "url": "https://api.voxburst.io/v1", "description": "Production API" }, { "url": "https://api-staging.voxburst.io/v1", "description": "Staging API" }, { "url": "http://localhost:3000/v1", "description": "Local development" } ], "tags": [ { "name": "Posts", "description": "Create, schedule, and manage social media posts" }, { "name": "Accounts", "description": "Connected social media accounts" }, { "name": "Workspaces", "description": "Workspace management and team collaboration" }, { "name": "Webhooks", "description": "Webhook configuration and delivery" }, { "name": "Analytics", "description": "Post and account analytics" }, { "name": "Media", "description": "Media upload and management" }, { "name": "AI", "description": "AI-powered content generation" }, { "name": "Billing", "description": "Subscription and billing management" }, { "name": "Health", "description": "API health and status endpoints" }, { "name": "Audit Logs", "description": "Audit logging and compliance" }, { "name": "Inbox", "description": "Social media engagement and comment management" }, { "name": "Invitations", "description": "Workspace invitation management" }, { "name": "Platforms", "description": "Supported social media platforms" }, { "name": "Queue", "description": "Publishing queue and scheduling slots" }, { "name": "Users", "description": "User profile and account management" }, { "name": "Workspace Members", "description": "Team member management" }, { "name": "API Keys", "description": "API key management with expiration tracking" }, { "name": "Status", "description": "Public platform operational status" }, { "name": "Batch", "description": "Batch operations and async job processing" }, { "name": "Contacts", "description": "Messaging contacts and one-off direct messages" }, { "name": "Broadcasts", "description": "One-to-many DM broadcasts and delivery tracking" }, { "name": "Sequences", "description": "Automated multi-step DM sequences and enrollments" } ], "security": [ { "BearerAuth": [] } ], "components": { "securitySchemes": { "BearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", "description": "Cognito JWT token or API key (vb_live_* or vb_test_*)" }, "ApiKey": { "type": "apiKey", "in": "header", "name": "Authorization", "description": "API key with Bearer prefix (Bearer vb_live_...)" } }, "schemas": { "ErrorResponse": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Machine-readable error code", "example": "VALIDATION_ERROR" }, "message": { "type": "string", "description": "Human-readable error message", "example": "Invalid request parameters" }, "details": { "type": "object", "additionalProperties": { "nullable": true }, "description": "Additional error details" }, "docs_url": { "type": "string", "format": "uri", "description": "Link to documentation for this error", "example": "https://docs.voxburst.io/errors/validation" } }, "required": [ "code", "message" ] } }, "required": [ "error" ] }, "RequestHistoryItem": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "method": { "type": "string", "example": "POST" }, "path": { "type": "string", "example": "/v1/posts" }, "statusCode": { "type": "integer", "example": 200 }, "responseTimeMs": { "type": "number", "nullable": true, "example": 142 }, "apiKeyId": { "type": "string", "nullable": true, "example": "key_abc123" }, "userAgent": { "type": "string", "nullable": true, "example": "VoxBurst-SDK/1.0" }, "ipAddress": { "type": "string", "nullable": true, "example": "203.0.113.42" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "method", "path", "statusCode", "responseTimeMs", "apiKeyId", "userAgent", "ipAddress", "createdAt" ] }, "ApiKeyUsageResponse": { "type": "object", "properties": { "key": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "prefix": { "type": "string" }, "scopes": { "type": "array", "items": { "type": "string" } }, "lastUsedAt": { "type": "string", "nullable": true, "format": "date-time" }, "revokedAt": { "type": "string", "nullable": true, "format": "date-time" }, "expiresAt": { "type": "string", "nullable": true, "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "name", "prefix", "scopes", "lastUsedAt", "revokedAt", "expiresAt", "createdAt" ] }, "period": { "type": "object", "properties": { "start": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "end": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "start", "end" ] }, "totalRequests": { "type": "integer" }, "avgResponseTimeMs": { "type": "number", "nullable": true }, "endpoints": { "type": "array", "items": { "type": "object", "properties": { "method": { "type": "string" }, "path": { "type": "string" }, "count": { "type": "integer" }, "errors": { "type": "integer" } }, "required": [ "method", "path", "count", "errors" ] } } }, "required": [ "key", "period", "totalRequests", "avgResponseTimeMs", "endpoints" ] }, "ErrorRatesResponse": { "type": "object", "properties": { "period": { "type": "object", "properties": { "start": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "end": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "start", "end" ] }, "totalRequests": { "type": "integer" }, "clientErrors": { "type": "integer", "description": "4xx error count" }, "serverErrors": { "type": "integer", "description": "5xx error count" }, "clientErrorRate": { "type": "number", "example": 0.02 }, "serverErrorRate": { "type": "number", "example": 0.005 }, "overallErrorRate": { "type": "number", "example": 0.025 }, "topEndpoints": { "type": "array", "items": { "type": "object", "properties": { "method": { "type": "string" }, "path": { "type": "string" }, "totalErrors": { "type": "integer" }, "clientErrors": { "type": "integer" }, "serverErrors": { "type": "integer" } }, "required": [ "method", "path", "totalErrors", "clientErrors", "serverErrors" ] } } }, "required": [ "period", "totalRequests", "clientErrors", "serverErrors", "clientErrorRate", "serverErrorRate", "overallErrorRate", "topEndpoints" ] }, "AsyncBatchJob": { "type": "object", "properties": { "jobId": { "type": "string", "example": "batch_abc123" }, "status": { "type": "string", "enum": [ "queued", "processing", "completed", "failed" ] }, "totalOperations": { "type": "integer" }, "completedOperations": { "type": "integer" }, "failedOperations": { "type": "integer" }, "results": { "type": "array", "nullable": true, "items": { "type": "object", "additionalProperties": { "nullable": true } } }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "completedAt": { "type": "string", "nullable": true, "format": "date-time" } }, "required": [ "jobId", "status", "totalOperations", "completedOperations", "failedOperations", "results", "createdAt", "completedAt" ] }, "PlatformStatus": { "type": "object", "properties": { "platform": { "type": "string", "example": "TWITTER" }, "status": { "type": "string", "enum": [ "operational", "degraded", "down" ] }, "lastSuccessfulPublish": { "type": "string", "nullable": true, "format": "date-time" }, "errorRateLastHour": { "type": "number", "example": 0.02 }, "totalPublishesLastHour": { "type": "integer", "example": 342 }, "checkedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "platform", "status", "lastSuccessfulPublish", "errorRateLastHour", "totalPublishesLastHour", "checkedAt" ] }, "PostMedia": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "url": { "type": "string", "format": "uri", "description": "URL of the media file" }, "type": { "type": "string", "enum": [ "image", "video", "gif" ], "description": "Type of media" }, "altText": { "type": "string", "description": "Alt text for accessibility" } }, "required": [ "id", "url", "type" ] }, "PlatformOverride": { "type": "object", "properties": { "content": { "type": "string", "maxLength": 10000, "description": "Platform-specific content override" } } }, "Post": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "workspaceId": { "type": "string", "format": "uuid", "description": "ID of the workspace this post belongs to", "example": "550e8400-e29b-41d4-a716-446655440000" }, "content": { "type": "string", "description": "Post content/text" }, "accountIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "Social account IDs to publish to (CUID format)", "example": [ "cmmmdwv6e0002yvot7ph96591", "cmn7dqf9k0003yvot8qj27356" ] }, "status": { "type": "string", "enum": [ "draft", "scheduled", "publishing", "published", "partial", "failed", "cancelled", "unpublished", "archived" ], "description": "Current status of the post. \"partial\" means published to some platforms but failed on others. \"cancelled\" means cancelled before publishing. \"archived\" means the post has been moved to an archived state (terminal; set by auto-archive cron or manually)." }, "scheduledFor": { "type": "string", "nullable": true, "format": "date-time", "description": "When the post is scheduled to publish", "example": "2024-02-26T12:00:00.000Z" }, "publishedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "When the post was actually published", "example": "2024-02-26T12:00:00.000Z" }, "media": { "type": "array", "items": { "$ref": "#/components/schemas/PostMedia" }, "description": "Attached media files" }, "platformOverrides": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/PlatformOverride" }, "description": "Platform-specific content overrides" }, "metadata": { "type": "object", "additionalProperties": { "nullable": true }, "description": "Custom metadata" }, "firstComment": { "type": "string", "nullable": true, "description": "First comment to post after publishing" }, "queuePosition": { "type": "number", "nullable": true, "description": "Position in the publishing queue" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "workspaceId", "content", "accountIds", "status", "scheduledFor", "publishedAt", "media", "createdAt", "updatedAt" ] }, "CreatePostRequest": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 10000, "description": "Post content/text", "example": "Check out our new feature! 🚀" }, "accountIds": { "type": "array", "items": { "type": "string", "minLength": 1 }, "minItems": 1, "maxItems": 10, "description": "Social account IDs to publish to (CUID format). Each account ID corresponds to a connected social media account in your workspace.", "example": [ "cmmmdwv6e0002yvot7ph96591", "cmn7dqf9k0003yvot8qj27356" ] }, "scheduledFor": { "type": "string", "format": "date-time", "description": "When to publish the post (ISO 8601). Must be in the future.", "example": "2024-02-27T15:00:00.000Z" }, "queue": { "type": "boolean", "description": "Add to publishing queue instead of specifying scheduledFor", "example": true }, "media": { "type": "array", "items": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "maxItems": 10, "description": "Media IDs to attach (max 10)" }, "platformOverrides": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/PlatformOverride" }, "description": "Platform-specific content overrides", "example": { "twitter": { "content": "Shorter version for Twitter" } } }, "metadata": { "type": "object", "additionalProperties": { "nullable": true }, "description": "Custom metadata to store with the post" }, "firstComment": { "type": "string", "maxLength": 2200, "description": "First comment to post after publishing (Instagram, LinkedIn)", "example": "Drop a 🔥 if you agree!" }, "firstCommentDelay": { "type": "integer", "minimum": 0, "maximum": 3600, "description": "Delay in seconds before posting first comment (0-3600)", "example": 60 } }, "required": [ "content", "accountIds" ] }, "PostListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Post" } }, "nextCursor": { "type": "string", "nullable": true, "description": "Cursor for the next page" }, "hasMore": { "type": "boolean", "description": "Whether more pages exist" } }, "required": [ "data", "nextCursor", "hasMore" ] }, "Platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ], "description": "Filter by target platform" }, "UpdatePostRequest": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 10000, "description": "Updated post content" }, "scheduledFor": { "type": "string", "format": "date-time", "description": "New scheduled time (ISO 8601)" }, "media": { "type": "array", "items": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "maxItems": 10, "description": "Updated media IDs" }, "platformOverrides": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/PlatformOverride" }, "description": "Updated platform-specific overrides" }, "metadata": { "type": "object", "additionalProperties": { "nullable": true }, "description": "Updated metadata" } } }, "PublishResponse": { "allOf": [ { "$ref": "#/components/schemas/Post" }, { "type": "object", "properties": { "timeout": { "type": "boolean", "description": "Present and true when sync mode timed out before reaching a terminal status" } } } ] }, "AccountPlatform": { "type": "string", "enum": [ "twitter", "linkedin", "instagram", "facebook", "bluesky", "tiktok", "youtube", "pinterest", "threads", "reddit", "snapchat", "telegram", "google_business", "mastodon", "whatsapp" ], "description": "Social media platform (lowercased on the wire)", "example": "instagram" }, "AccountStatus": { "type": "string", "enum": [ "active", "expired", "revoked", "disconnected" ], "description": "Connection status of the social account (lowercased on the wire)" }, "FlobProbe": { "type": "object", "properties": { "flobAvailable": { "type": "boolean" }, "facebookAccountId": { "type": "string" }, "facebookPlatformUserId": { "type": "string" }, "pageId": { "type": "string" }, "checkedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "flobAvailable", "checkedAt" ], "description": "Instagram only: whether a connected Facebook account can unlock Facebook Login for Business. Omitted when no probe has run." }, "ScopeHealth": { "type": "object", "properties": { "status": { "type": "string", "description": "OK | DEGRADED | UNKNOWN | NOT_APPLICABLE", "example": "DEGRADED" }, "degradedCapabilities": { "type": "array", "items": { "type": "object", "properties": { "capability": { "type": "string", "description": "Machine-readable capability identifier" }, "label": { "type": "string", "description": "User-facing capability name. Never a raw scope name." }, "grantedForOtherTargetsOnly": { "type": "boolean", "description": "Granted for a different Page/account rather than missing outright. Omitted when false." } }, "required": [ "capability", "label" ] }, "description": "Capabilities that cannot work with the permissions the platform granted." }, "message": { "type": "string", "description": "One user-facing sentence. Omitted when the account is healthy." }, "reason": { "type": "string", "description": "Why the granted set is unknown or not applicable. Omitted when not set." }, "verifiedAt": { "type": "string", "format": "date-time", "description": "When scopes were last verified. Omitted if never verified.", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "status", "degradedCapabilities" ], "description": "Scope verification result: computed at connect time and re-evaluated daily by the account-health worker against current capability requirements. Also reports the legacy YouTube playlist / LinkedIn organization reauth conditions as `DEGRADED`, so this one field covers every known permission gap. **Absent on accounts connected before verification shipped and with no legacy gap — absent is NOT the same as healthy.** Treat a missing `scopeHealth` as unknown, never as OK." }, "Account": { "type": "object", "properties": { "id": { "type": "string", "description": "Account ID", "example": "clx1a2b3c4d5e6f7g8h9i0j1" }, "platform": { "$ref": "#/components/schemas/AccountPlatform" }, "username": { "type": "string", "nullable": true, "description": "Platform username/handle. Null when the platform does not expose one.", "example": "acmecorp" }, "displayName": { "type": "string", "nullable": true, "description": "Human-readable account name. Null when unknown.", "example": "Acme Corp" }, "avatarUrl": { "type": "string", "nullable": true, "description": "Profile picture URL. Null when the platform did not supply one." }, "accountType": { "type": "string", "nullable": true, "description": "Platform-specific account classification (e.g. business, creator). Null when not applicable.", "example": "business" }, "status": { "$ref": "#/components/schemas/AccountStatus" }, "connectedAt": { "type": "string", "format": "date-time", "description": "When the account was connected.", "example": "2024-02-26T12:00:00.000Z" }, "followers": { "type": "integer", "description": "Follower count from the most recent metrics snapshot. **Omitted** (not null) when no snapshot with a follower count exists.", "example": 1042 }, "oauthVersion": { "type": "string", "description": "Instagram only: `fb_login` (Facebook Login / FLOB) or `instagram_login` (Instagram Direct). Omitted for other platforms and for Instagram accounts with no recorded version.", "example": "instagram_login" }, "flobProbe": { "$ref": "#/components/schemas/FlobProbe" }, "needsPlaylistReauth": { "type": "boolean", "description": "YouTube only: true when the connection predates the full `youtube` scope and cannot manage playlists until reconnected. Omitted for other platforms." }, "needsOrgScopeReauth": { "type": "boolean", "description": "LinkedIn only: true when the connection lacks `w_organization_social` and cannot post to company pages until reconnected. Omitted for other platforms, and omitted entirely while organization scopes are disabled server-side." }, "gmbLocationsConfigured": { "type": "boolean", "description": "Google Business only: true when at least one location has been selected to sync. Omitted for other platforms." }, "scopeHealth": { "$ref": "#/components/schemas/ScopeHealth" } }, "required": [ "id", "platform", "username", "displayName", "avatarUrl", "accountType", "status", "connectedAt" ], "description": "A connected social account. Platform-conditional fields (`oauthVersion`, `flobProbe`, `needsPlaylistReauth`, `needsOrgScopeReauth`, `gmbLocationsConfigured`, `scopeHealth`) are omitted from the payload rather than returned as null — check for key presence, not for null." }, "AccountListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Account" } }, "pagination": { "type": "object", "properties": { "has_more": { "type": "boolean", "description": "Whether more accounts are available after this page" }, "next_cursor": { "type": "string", "nullable": true, "description": "Cursor for the next page. Null when there are no more pages." }, "limit": { "type": "integer", "description": "Page size that was applied", "example": 20 } }, "required": [ "has_more", "next_cursor", "limit" ] } }, "required": [ "data", "pagination" ] }, "WebhookEndpoint": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "workspaceId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "url": { "type": "string", "format": "uri", "description": "HTTPS URL to receive webhook events", "example": "https://api.example.com/webhooks/voxburst" }, "events": { "type": "array", "items": { "type": "string", "enum": [ "post.created", "post.scheduled", "post.published", "post.failed", "post.draft.approved", "account.connected", "account.disconnected", "account.error", "media.uploaded" ], "description": "Type of event that triggers the webhook. Subscribable events only — additional internal events may be fired but cannot be subscribed to." }, "description": "Event types this endpoint subscribes to" }, "enabled": { "type": "boolean", "description": "Whether the endpoint is active" }, "description": { "type": "string", "nullable": true, "description": "Optional description" }, "metadata": { "type": "object", "nullable": true, "additionalProperties": { "nullable": true }, "description": "Custom metadata" }, "consecutiveFailures": { "type": "integer", "description": "Number of consecutive failed deliveries. Resets to 0 on a successful delivery. When this reaches 5, the workspace owner receives an email notification.", "example": 0 }, "lastFailureAt": { "type": "string", "nullable": true, "format": "date-time", "description": "Timestamp of the last failed delivery, or null if no failures have occurred.", "example": "2024-02-26T12:00:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "workspaceId", "url", "events", "enabled", "description", "metadata", "consecutiveFailures", "lastFailureAt", "createdAt", "updatedAt" ] }, "WebhookEndpointWithSecret": { "allOf": [ { "$ref": "#/components/schemas/WebhookEndpoint" }, { "type": "object", "properties": { "secret": { "type": "string", "description": "Signing secret (only shown once on creation)", "example": "whsec_abc123..." } }, "required": [ "secret" ] } ] }, "CreateWebhookEndpointRequest": { "type": "object", "properties": { "url": { "type": "string", "format": "uri", "description": "HTTPS URL to receive webhook events", "example": "https://api.example.com/webhooks/voxburst" }, "events": { "type": "array", "items": { "type": "string", "enum": [ "post.created", "post.scheduled", "post.published", "post.failed", "post.draft.approved", "account.connected", "account.disconnected", "account.error", "media.uploaded" ], "description": "Type of event that triggers the webhook. Subscribable events only — additional internal events may be fired but cannot be subscribed to." }, "minItems": 1, "description": "Event types to subscribe to", "example": [ "post.published", "post.failed" ] }, "description": { "type": "string", "maxLength": 500, "description": "Optional description" }, "metadata": { "type": "object", "additionalProperties": { "nullable": true }, "description": "Custom metadata" } }, "required": [ "url", "events" ] }, "UpdateWebhookEndpointRequest": { "type": "object", "properties": { "url": { "type": "string", "format": "uri", "description": "Updated webhook URL" }, "events": { "type": "array", "items": { "type": "string", "enum": [ "post.created", "post.scheduled", "post.published", "post.failed", "post.draft.approved", "account.connected", "account.disconnected", "account.error", "media.uploaded" ], "description": "Type of event that triggers the webhook. Subscribable events only — additional internal events may be fired but cannot be subscribed to." }, "minItems": 1, "description": "Updated event subscriptions" }, "enabled": { "type": "boolean", "description": "Enable or disable the endpoint" }, "description": { "type": "string", "maxLength": 500, "description": "Updated description" } } }, "WebhookDelivery": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "endpointId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "event": { "type": "string", "enum": [ "post.created", "post.scheduled", "post.published", "post.failed", "post.draft.approved", "account.connected", "account.disconnected", "account.error", "media.uploaded" ], "description": "Type of event that triggers the webhook. Subscribable events only — additional internal events may be fired but cannot be subscribed to." }, "payload": { "type": "object", "additionalProperties": { "nullable": true }, "description": "The event payload that was sent" }, "statusCode": { "type": "number", "nullable": true, "description": "HTTP status code from the target" }, "response": { "type": "string", "nullable": true, "description": "Response body from the target" }, "success": { "type": "boolean", "description": "Whether delivery was successful" }, "attempts": { "type": "number", "description": "Number of delivery attempts" }, "deliveredAt": { "type": "string", "nullable": true, "format": "date-time", "description": "When successfully delivered", "example": "2024-02-26T12:00:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "endpointId", "event", "payload", "statusCode", "response", "success", "attempts", "deliveredAt", "createdAt" ] }, "Workspace": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "name": { "type": "string", "description": "Workspace name", "example": "Acme Marketing" }, "slug": { "type": "string", "description": "URL-friendly identifier", "example": "acme-marketing" }, "avatarUrl": { "type": "string", "nullable": true, "format": "uri", "description": "Workspace logo URL" }, "plan": { "type": "string", "enum": [ "FREE", "STARTER", "PRO", "AGENCY" ], "description": "Current subscription plan" }, "metadata": { "type": "object", "nullable": true, "additionalProperties": { "nullable": true }, "description": "Custom metadata" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "name", "slug", "avatarUrl", "plan", "metadata", "createdAt", "updatedAt" ] }, "CreateWorkspaceRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Workspace name", "example": "My Team" }, "slug": { "type": "string", "minLength": 1, "maxLength": 50, "pattern": "^[a-z0-9-]+$", "description": "URL-friendly identifier (auto-generated if not provided)", "example": "my-team" } }, "required": [ "name" ] }, "UpdateWorkspaceRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Updated workspace name" }, "avatarUrl": { "type": "string", "nullable": true, "format": "uri", "description": "Updated logo URL" } } }, "WorkspaceMember": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "userId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "workspaceId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "role": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ], "description": "Role in the workspace" }, "user": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "email": { "type": "string", "format": "email" }, "name": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true, "format": "uri" } }, "required": [ "id", "email", "name", "avatarUrl" ] }, "joinedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "userId", "workspaceId", "role", "user", "joinedAt" ] }, "InviteMemberRequest": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "Email address to invite", "example": "colleague@example.com" }, "role": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ], "default": "MEMBER", "description": "Role to assign" } }, "required": [ "email" ] }, "UpdateMemberRoleRequest": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ], "description": "New role for the member" } }, "required": [ "role" ] }, "UploadUrlResponse": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Media ID (use when attaching to posts)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "uploadUrl": { "type": "string", "format": "uri", "description": "Pre-signed URL for upload" }, "fields": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Form fields for multipart upload (S3)" }, "expiresAt": { "type": "string", "format": "date-time", "description": "When the upload URL expires", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "uploadUrl", "expiresAt" ] }, "RequestUploadUrlRequest": { "type": "object", "properties": { "filename": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Original filename", "example": "product-photo.jpg" }, "contentType": { "type": "string", "description": "MIME type of the file", "example": "image/jpeg" }, "size": { "type": "integer", "minimum": 1, "maximum": 52428800, "description": "File size in bytes (max 50MB)", "example": 1024000 } }, "required": [ "filename", "contentType", "size" ] }, "Media": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "workspaceId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "filename": { "type": "string", "description": "Original filename", "example": "product-photo.jpg" }, "type": { "type": "string", "enum": [ "image", "video", "gif" ], "description": "Type of media file" }, "mimeType": { "type": "string", "description": "MIME type of the file", "example": "image/jpeg" }, "size": { "type": "number", "description": "File size in bytes", "example": 1024000 }, "url": { "type": "string", "format": "uri", "description": "URL to access the media" }, "thumbnailUrl": { "type": "string", "nullable": true, "format": "uri", "description": "URL of thumbnail (for images/videos)" }, "width": { "type": "number", "nullable": true, "description": "Width in pixels", "example": 1200 }, "height": { "type": "number", "nullable": true, "description": "Height in pixels", "example": 800 }, "duration": { "type": "number", "nullable": true, "description": "Duration in seconds (for videos)" }, "altText": { "type": "string", "nullable": true, "description": "Alt text for accessibility" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "workspaceId", "filename", "type", "mimeType", "size", "url", "thumbnailUrl", "width", "height", "duration", "altText", "createdAt" ] }, "GeneratedContent": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "content": { "type": "string", "description": "Generated post content", "example": "🚀 Exciting news! We just launched our new feature..." }, "platform": { "type": "string", "description": "Platform this content is optimized for" }, "characterCount": { "type": "number", "description": "Length of the content" }, "hashtagsUsed": { "type": "array", "items": { "type": "string" }, "description": "Hashtags included in the content" } }, "required": [ "id", "content", "characterCount", "hashtagsUsed" ] }, "AIUsage": { "type": "object", "properties": { "used": { "type": "number", "description": "AI generations used this billing period", "example": 45 }, "limit": { "type": "number", "description": "AI generation limit for the current plan", "example": 100 }, "resetAt": { "type": "string", "format": "date-time", "description": "When usage resets", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "used", "limit", "resetAt" ] }, "GenerateContentRequest": { "type": "object", "properties": { "prompt": { "type": "string", "minLength": 1, "maxLength": 2000, "description": "Prompt describing what to generate", "example": "Write a LinkedIn post announcing our Series A funding" }, "platforms": { "type": "array", "items": { "type": "string" }, "description": "Optimize for specific platforms", "example": [ "twitter", "linkedin" ] }, "tone": { "type": "string", "enum": [ "professional", "casual", "humorous", "inspirational", "informative" ], "description": "Desired tone/voice" }, "includeEmojis": { "type": "boolean", "default": true, "description": "Include emojis in generated content" }, "includeHashtags": { "type": "boolean", "default": true, "description": "Include relevant hashtags" }, "maxLength": { "type": "integer", "minimum": 50, "maximum": 5000, "description": "Maximum character length", "example": 280 }, "variations": { "type": "integer", "minimum": 1, "maximum": 5, "default": 3, "description": "Number of variations to generate", "example": 3 }, "context": { "type": "string", "maxLength": 5000, "description": "Additional context about your brand/product" } }, "required": [ "prompt" ] }, "ImproveContentRequest": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 10000, "description": "Original content to improve" }, "instructions": { "type": "string", "maxLength": 500, "description": "Specific improvement instructions", "example": "Make it more engaging and add a call to action" }, "platform": { "type": "string", "description": "Optimize for this platform" } }, "required": [ "content" ] }, "BatchItemResult": { "type": "object", "properties": { "index": { "type": "integer", "description": "Index of the item in the request array" }, "success": { "type": "boolean", "description": "Whether this operation succeeded" }, "data": { "nullable": true, "description": "Result data (on success)" }, "error": { "type": "object", "nullable": true, "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": [ "code", "message" ], "description": "Error details (on failure)" } }, "required": [ "index", "success", "error" ] }, "BatchResponse": { "type": "object", "properties": { "total": { "type": "integer", "description": "Total items processed" }, "successful": { "type": "integer", "description": "Number of successful operations" }, "failed": { "type": "integer", "description": "Number of failed operations" }, "results": { "type": "array", "items": { "$ref": "#/components/schemas/BatchItemResult" }, "description": "Individual results for each item" } }, "required": [ "total", "successful", "failed", "results" ] }, "BatchCreatePost": { "type": "object", "properties": { "operation": { "type": "string", "enum": [ "create" ] }, "data": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 10000 }, "platforms": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "scheduledFor": { "type": "string", "format": "date-time" }, "media": { "type": "array", "items": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" } }, "platformOverrides": { "type": "object", "additionalProperties": { "type": "object", "properties": { "content": { "type": "string" } } } } }, "required": [ "content", "platforms" ] } }, "required": [ "operation", "data" ] }, "BatchUpdatePost": { "type": "object", "properties": { "operation": { "type": "string", "enum": [ "update" ] }, "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "data": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 10000 }, "scheduledFor": { "type": "string", "format": "date-time" }, "media": { "type": "array", "items": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" } } } } }, "required": [ "operation", "id", "data" ] }, "BatchDeletePost": { "type": "object", "properties": { "operation": { "type": "string", "enum": [ "delete" ] }, "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" } }, "required": [ "operation", "id" ] }, "BatchPostOperation": { "anyOf": [ { "$ref": "#/components/schemas/BatchCreatePost" }, { "$ref": "#/components/schemas/BatchUpdatePost" }, { "$ref": "#/components/schemas/BatchDeletePost" } ] }, "BatchPostsRequest": { "type": "object", "properties": { "operations": { "type": "array", "items": { "$ref": "#/components/schemas/BatchPostOperation" }, "minItems": 1, "maxItems": 100, "description": "Array of post operations (max 100)" } }, "required": [ "operations" ] }, "ServiceHealth": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "healthy", "degraded", "unhealthy" ], "description": "Health status indicator" }, "latencyMs": { "type": "number", "nullable": true, "description": "Response latency in milliseconds" }, "message": { "type": "string", "description": "Additional status message" } }, "required": [ "status", "latencyMs" ] }, "HealthResponse": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "ok", "degraded", "unhealthy" ], "description": "Overall API health" }, "timestamp": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "version": { "type": "string", "description": "API version", "example": "1.0.0" }, "services": { "type": "object", "properties": { "database": { "$ref": "#/components/schemas/ServiceHealth" }, "jwks": { "$ref": "#/components/schemas/ServiceHealth" }, "storage": { "$ref": "#/components/schemas/ServiceHealth" } }, "description": "Individual service health status" } }, "required": [ "status", "timestamp", "version" ] }, "JwksHealth": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "cached", "stale", "unreachable" ], "description": "JWKS cache status" }, "keyCount": { "type": "integer", "description": "Number of cached keys" }, "cachedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "When keys were last cached", "example": "2024-02-26T12:00:00.000Z" }, "expiresAt": { "type": "string", "nullable": true, "format": "date-time", "description": "When cache expires", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "status", "keyCount", "cachedAt", "expiresAt" ] }, "WorkflowStep": { "type": "object", "properties": { "order": { "type": "integer", "minimum": 1, "description": "Step order (starting at 1)" }, "role": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Role label", "example": "Content Manager" }, "approverIds": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "User IDs who can approve this step" }, "required": { "type": "boolean", "default": true, "description": "Whether this step is required" } }, "required": [ "order", "role", "approverIds" ] }, "ApprovalStepStatus": { "type": "object", "properties": { "order": { "type": "integer" }, "role": { "type": "string" }, "status": { "type": "string", "enum": [ "PENDING", "APPROVED", "REJECTED" ] }, "approvedBy": { "type": "string", "nullable": true }, "approvedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "comment": { "type": "string", "nullable": true } }, "required": [ "order", "role", "status", "approvedBy", "approvedAt" ] }, "PostAnalyticsItem": { "type": "object", "properties": { "postId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "postPlatformId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ] }, "platformPostId": { "type": "string", "nullable": true }, "platformPostUrl": { "type": "string", "nullable": true }, "metrics": { "type": "object", "properties": { "impressions": { "type": "integer" }, "reach": { "type": "integer" }, "engagements": { "type": "integer" }, "likes": { "type": "integer" }, "comments": { "type": "integer" }, "shares": { "type": "integer" }, "clicks": { "type": "integer" }, "saves": { "type": "integer" }, "videoViews": { "type": "integer", "nullable": true }, "videoWatchTimeMs": { "type": "integer", "nullable": true } }, "required": [ "impressions", "reach", "engagements", "likes", "comments", "shares", "clicks", "saves" ] }, "dataAvailable": { "type": "boolean", "description": "False when the platform failed to return its headline metric for this row" }, "collectedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "periodStart": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "periodEnd": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "granularity": { "type": "string", "enum": [ "HOURLY", "DAILY", "WEEKLY", "MONTHLY" ], "description": "Time granularity for metrics aggregation", "example": "DAILY" } }, "required": [ "postId", "postPlatformId", "platform", "platformPostId", "platformPostUrl", "metrics", "dataAvailable", "collectedAt", "periodStart", "periodEnd", "granularity" ] }, "ListPostAnalyticsResponse": { "type": "object", "properties": { "posts": { "type": "array", "items": { "$ref": "#/components/schemas/PostAnalyticsItem" } }, "has_more": { "type": "boolean" }, "next_cursor": { "type": "string", "nullable": true } }, "required": [ "posts", "has_more", "next_cursor" ] }, "PostMetrics": { "type": "object", "properties": { "timestamp": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "granularity": { "type": "string", "enum": [ "HOURLY", "DAILY", "WEEKLY", "MONTHLY" ], "description": "Time granularity for metrics aggregation", "example": "DAILY" }, "impressions": { "type": "integer", "minimum": 0, "description": "Total impressions" }, "reach": { "type": "integer", "minimum": 0, "description": "Unique users reached" }, "likes": { "type": "integer", "minimum": 0 }, "comments": { "type": "integer", "minimum": 0 }, "shares": { "type": "integer", "minimum": 0 }, "clicks": { "type": "integer", "minimum": 0 }, "saves": { "type": "integer", "minimum": 0 }, "engagementRate": { "type": "number", "minimum": 0, "maximum": 100, "description": "Engagement rate percentage" } }, "required": [ "timestamp", "granularity", "impressions", "reach", "likes", "comments", "shares", "clicks", "saves", "engagementRate" ] }, "PostMetricsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PostMetrics" } } }, "required": [ "data" ] }, "AccountMetrics": { "type": "object", "properties": { "accountId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ], "description": "Social media platform" }, "followers": { "type": "integer", "minimum": 0, "description": "Current follower count" }, "followersChange": { "type": "integer", "description": "Follower change in period" }, "postsPublished": { "type": "integer", "minimum": 0 }, "periodStart": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "periodEnd": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "dailyMetrics": { "type": "array", "items": { "$ref": "#/components/schemas/PostMetrics" } } }, "required": [ "accountId", "platform", "followers", "followersChange", "postsPublished", "periodStart", "periodEnd" ] }, "AggregateMetrics": { "type": "object", "properties": { "totalPosts": { "type": "integer", "minimum": 0 }, "totalImpressions": { "type": "integer", "minimum": 0 }, "totalEngagements": { "type": "integer", "minimum": 0 }, "averageEngagementRate": { "type": "number", "minimum": 0, "maximum": 100 }, "byPlatform": { "type": "object", "additionalProperties": { "type": "object", "properties": { "posts": { "type": "integer" }, "impressions": { "type": "integer" }, "engagements": { "type": "integer" } }, "required": [ "posts", "impressions", "engagements" ] } }, "topPerformingPosts": { "type": "array", "items": { "type": "object", "properties": { "postId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "content": { "type": "string" }, "impressions": { "type": "integer" }, "engagementRate": { "type": "number" } }, "required": [ "postId", "content", "impressions", "engagementRate" ] } }, "periodStart": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "periodEnd": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "totalPosts", "totalImpressions", "totalEngagements", "averageEngagementRate", "byPlatform", "topPerformingPosts", "periodStart", "periodEnd" ] }, "AnalyticsOverview": { "type": "object", "properties": { "summary": { "type": "object", "properties": { "totalPosts": { "type": "integer" }, "totalImpressions": { "type": "integer" }, "totalEngagements": { "type": "integer" }, "averageEngagementRate": { "type": "number" } }, "required": [ "totalPosts", "totalImpressions", "totalEngagements", "averageEngagementRate" ] }, "topPosts": { "type": "array", "items": { "type": "object", "properties": { "postId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "content": { "type": "string" }, "impressions": { "type": "integer" }, "engagementRate": { "type": "number" } }, "required": [ "postId", "content", "impressions", "engagementRate" ] } }, "byPlatform": { "type": "object", "additionalProperties": { "type": "object", "properties": { "posts": { "type": "integer" }, "impressions": { "type": "integer" }, "engagements": { "type": "integer" } }, "required": [ "posts", "impressions", "engagements" ] } }, "period": { "type": "object", "properties": { "start": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "end": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "start", "end" ] } }, "required": [ "summary", "topPosts", "byPlatform", "period" ] }, "RefreshMetricsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PostMetrics" } }, "refreshedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "data", "refreshedAt" ] }, "AuditLog": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "timestamp": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "actorType": { "type": "string", "enum": [ "user", "api_key", "system" ], "description": "Type of actor who performed the action" }, "actorId": { "type": "string", "nullable": true, "description": "User ID or API key ID" }, "apiKeyId": { "type": "string", "nullable": true }, "action": { "type": "string", "enum": [ "create", "update", "delete" ], "description": "Type of action performed" }, "resourceType": { "type": "string", "nullable": true, "description": "Type of resource (posts, accounts, etc.)" }, "resourceId": { "type": "string", "nullable": true }, "method": { "type": "string", "description": "HTTP method" }, "path": { "type": "string", "description": "API endpoint path" }, "statusCode": { "type": "integer", "nullable": true }, "ipAddress": { "type": "string", "nullable": true }, "userAgent": { "type": "string", "nullable": true }, "requestId": { "type": "string", "nullable": true } }, "required": [ "id", "timestamp", "actorType", "actorId", "action", "resourceType", "resourceId", "method", "path", "statusCode", "ipAddress", "userAgent", "requestId" ] }, "AuditLogListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AuditLog" } }, "pagination": { "type": "object", "properties": { "has_more": { "type": "boolean" }, "next_cursor": { "type": "string", "nullable": true }, "limit": { "type": "integer" } }, "required": [ "has_more", "next_cursor", "limit" ] } }, "required": [ "data", "pagination" ] }, "AuditLogStats": { "type": "object", "properties": { "total": { "type": "integer" }, "byAction": { "type": "object", "additionalProperties": { "type": "integer" } }, "byResourceType": { "type": "object", "additionalProperties": { "type": "integer" } } }, "required": [ "total", "byAction", "byResourceType" ] }, "AuditLogStatsResponse": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AuditLogStats" } }, "required": [ "data" ] }, "AiAddon": { "type": "object", "nullable": true, "properties": { "subscribed": { "type": "boolean" }, "entitled": { "type": "boolean" }, "source": { "type": "string", "enum": [ "plan", "addon", "complimentary" ] }, "tier": { "type": "string", "nullable": true, "enum": [ "starter", "pro", "COMPLIMENTARY" ] }, "creditsUsed": { "type": "integer", "minimum": 0 }, "creditsLimit": { "type": "integer", "nullable": true }, "creditsRemaining": { "type": "integer", "nullable": true }, "billingPeriodEnd": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "subscribed", "entitled", "source", "tier", "creditsUsed", "creditsLimit", "creditsRemaining", "billingPeriodEnd" ] }, "BillingCurrent": { "type": "object", "properties": { "plan": { "type": "string", "enum": [ "free", "starter", "pro", "agency" ] }, "billingInterval": { "type": "string", "enum": [ "monthly", "annual" ] }, "status": { "type": "string", "enum": [ "active", "trialing", "past_due", "canceled", "incomplete" ] }, "currentPeriodStart": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "currentPeriodEnd": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "trialEnd": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 timestamp when the trial ends. Null if no trial.", "example": "2024-02-26T12:00:00.000Z" }, "trialTotalDays": { "type": "integer", "nullable": true, "description": "Total number of trial days (computed from trial_start/trial_end). Null if no trial." }, "recentlyExpiredTrial": { "type": "boolean", "description": "True when this workspace's trial has expired and no post-trial plan choice has been recorded for it yet. There is no time window — the flag stays true until an owner or admin selects a plan or acknowledges the trial ending, and it is scoped to this workspace rather than to the caller." }, "cancelAtPeriodEnd": { "type": "boolean" }, "currentAmountCents": { "type": "integer", "minimum": 0 }, "isFoundingPrice": { "type": "boolean" }, "pendingDowngrade": { "type": "string", "nullable": true }, "pendingDowngradeEffective": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "aiAddon": { "$ref": "#/components/schemas/AiAddon" }, "subscriptionId": { "type": "string", "nullable": true }, "billingSource": { "type": "string", "enum": [ "STRIPE", "MANUAL", "SYSTEM" ] }, "providerStatus": { "type": "string", "enum": [ "available", "unavailable", "not_applicable" ] }, "entitlement": { "type": "object", "properties": { "plan": { "type": "string", "enum": [ "free", "starter", "pro", "agency" ] }, "status": { "type": "string", "enum": [ "active", "trialing", "past_due", "canceled", "incomplete", "unpaid", "unknown" ] }, "hasPlanAccess": { "type": "boolean" }, "reason": { "type": "string", "enum": [ "active_subscription", "active_trial", "past_due_grace", "expired_trial", "inactive_subscription", "no_subscription" ] } }, "required": [ "plan", "status", "hasPlanAccess", "reason" ] } }, "required": [ "plan", "billingInterval", "status", "currentPeriodStart", "currentPeriodEnd", "trialEnd", "trialTotalDays", "recentlyExpiredTrial", "cancelAtPeriodEnd", "currentAmountCents", "isFoundingPrice", "pendingDowngrade", "pendingDowngradeEffective", "aiAddon", "subscriptionId", "billingSource", "providerStatus", "entitlement" ] }, "Plan": { "type": "object", "properties": { "id": { "type": "string", "enum": [ "starter", "pro", "agency" ], "description": "Subscription plan ID" }, "name": { "type": "string" }, "description": { "type": "string" }, "priceMonthly": { "type": "integer", "minimum": 0 }, "priceYearly": { "type": "integer", "minimum": 0 }, "limits": { "type": "object", "properties": { "maxWorkspaces": { "type": "integer" }, "maxAccountsPerOrg": { "type": "integer" }, "maxPostsPerMonth": { "type": "integer", "nullable": true }, "maxTeamMembers": { "type": "integer" }, "aiEnabled": { "type": "boolean" } }, "required": [ "maxWorkspaces", "maxAccountsPerOrg", "maxPostsPerMonth", "maxTeamMembers", "aiEnabled" ] }, "popular": { "type": "boolean" } }, "required": [ "id", "name", "description", "priceMonthly", "priceYearly", "limits" ] }, "PlansResponse": { "type": "object", "properties": { "plans": { "type": "array", "items": { "$ref": "#/components/schemas/Plan" } } }, "required": [ "plans" ] }, "CheckoutSession": { "type": "object", "properties": { "sessionId": { "type": "string" }, "url": { "type": "string", "format": "uri" } }, "required": [ "sessionId", "url" ] }, "CheckoutRequest": { "type": "object", "properties": { "planId": { "type": "string", "enum": [ "starter", "pro", "agency" ], "description": "Subscription plan ID" }, "billingPeriod": { "type": "string", "enum": [ "monthly", "yearly" ], "default": "monthly", "description": "Billing period" }, "successUrl": { "type": "string", "format": "uri" }, "cancelUrl": { "type": "string", "format": "uri" } }, "required": [ "planId", "successUrl", "cancelUrl" ] }, "PortalResponse": { "type": "object", "properties": { "url": { "type": "string", "format": "uri" } }, "required": [ "url" ] }, "PortalRequest": { "type": "object", "properties": { "returnUrl": { "type": "string", "format": "uri" } }, "required": [ "returnUrl" ] }, "Subscription": { "type": "object", "properties": { "plan": { "type": "string", "enum": [ "free", "starter", "pro", "agency" ] }, "status": { "type": "string", "enum": [ "ACTIVE", "CANCELLED", "PAST_DUE", "UNPAID", "TRIALING" ], "description": "Subscription status" }, "currentPeriodStart": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "currentPeriodEnd": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "cancelAtPeriodEnd": { "type": "boolean" }, "limits": { "type": "object", "properties": { "maxWorkspaces": { "type": "integer" }, "maxAccountsPerOrg": { "type": "integer" }, "maxPostsPerMonth": { "type": "integer", "nullable": true }, "maxTeamMembers": { "type": "integer" }, "aiEnabled": { "type": "boolean" } }, "required": [ "maxWorkspaces", "maxAccountsPerOrg", "maxPostsPerMonth", "maxTeamMembers", "aiEnabled" ] } }, "required": [ "plan", "status", "currentPeriodStart", "currentPeriodEnd", "cancelAtPeriodEnd", "limits" ] }, "UsageLimit": { "type": "object", "properties": { "used": { "type": "integer", "minimum": 0 }, "limit": { "type": "integer", "minimum": 0 } }, "required": [ "used", "limit" ] }, "UsageResponse": { "type": "object", "properties": { "plan": { "type": "string", "enum": [ "free", "starter", "pro", "agency" ] }, "usage": { "type": "object", "properties": { "workspaces": { "$ref": "#/components/schemas/UsageLimit" }, "accounts": { "$ref": "#/components/schemas/UsageLimit" }, "posts": { "$ref": "#/components/schemas/UsageLimit" } }, "required": [ "workspaces", "accounts", "posts" ] }, "features": { "type": "object", "properties": { "aiEnabled": { "type": "boolean" } }, "required": [ "aiEnabled" ] }, "billing": { "type": "object", "properties": { "currentPeriodStart": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "currentPeriodEnd": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "cancelAtPeriodEnd": { "type": "boolean" } }, "required": [ "currentPeriodStart", "currentPeriodEnd", "cancelAtPeriodEnd" ] } }, "required": [ "plan", "usage", "features", "billing" ] }, "Comment": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "platform": { "type": "string", "description": "Social media platform" }, "externalId": { "type": "string", "description": "Platform-specific comment ID" }, "postExternalId": { "type": "string", "description": "Platform-specific post ID" }, "authorUsername": { "type": "string", "nullable": true }, "authorDisplayName": { "type": "string", "nullable": true }, "authorAvatarUrl": { "type": "string", "nullable": true, "format": "uri" }, "content": { "type": "string", "description": "Comment text content" }, "replied": { "type": "boolean", "description": "Whether this comment has been replied to" }, "replyId": { "type": "string", "nullable": true, "description": "ID of the reply comment if any" }, "replyUrl": { "type": "string", "nullable": true, "format": "uri" }, "replyContent": { "type": "string", "nullable": true }, "repliedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "hidden": { "type": "boolean", "description": "Whether the comment is soft-hidden and excluded from the default inbox list. Hiding is a VoxBurst-side visibility control and does not affect the comment on the source platform." }, "hiddenAt": { "type": "string", "nullable": true, "format": "date-time", "description": "When the comment was hidden. Null when the comment is not hidden.", "example": "2024-02-26T12:00:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "platform", "externalId", "postExternalId", "authorUsername", "authorDisplayName", "authorAvatarUrl", "content", "replied", "replyId", "replyUrl", "replyContent", "repliedAt", "hidden", "hiddenAt", "createdAt", "updatedAt" ] }, "CommentListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Comment" } }, "pagination": { "type": "object", "properties": { "hasMore": { "type": "boolean" }, "nextCursor": { "type": "string", "nullable": true }, "limit": { "type": "integer" } }, "required": [ "hasMore", "nextCursor", "limit" ] } }, "required": [ "data", "pagination" ] }, "CommentStats": { "type": "object", "properties": { "total": { "type": "integer" }, "pending": { "type": "integer" }, "replied": { "type": "integer" }, "byPlatform": { "type": "object", "additionalProperties": { "type": "integer" } } }, "required": [ "total", "pending", "replied", "byPlatform" ] }, "ReplyResponse": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] }, "replyId": { "type": "string", "nullable": true }, "replyUrl": { "type": "string", "nullable": true, "format": "uri" } }, "required": [ "success", "replyId", "replyUrl" ] }, "ReplyToCommentRequest": { "type": "object", "properties": { "content": { "type": "string", "minLength": 1, "maxLength": 10000, "description": "Reply content", "example": "Thanks for your comment! 🙏" } }, "required": [ "content" ] }, "HideCommentResponse": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Comment" } }, "required": [ "data" ] }, "SyncCommentsResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "totalSynced": { "type": "integer" }, "totalErrors": { "type": "integer" }, "accounts": { "type": "array", "items": { "type": "object", "properties": { "accountId": { "type": "string" }, "platform": { "type": "string" }, "synced": { "type": "integer" }, "errors": { "type": "array", "items": { "type": "string" } }, "message": { "type": "string" } }, "required": [ "accountId", "platform", "synced", "errors", "message" ] } } }, "required": [ "success", "totalSynced", "totalErrors", "accounts" ] }, "PendingInvitation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "workspaceId": { "type": "string" }, "workspace": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "logo": { "type": "string", "nullable": true } }, "required": [ "id", "name", "slug", "logo" ] }, "role": { "type": "string", "enum": [ "ADMIN", "MEMBER", "VIEWER" ], "description": "Role assigned to the invited user" }, "invitedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "invitedByUserId": { "type": "string", "nullable": true } }, "required": [ "id", "workspaceId", "workspace", "role", "invitedAt", "invitedByUserId" ] }, "ListInvitationsResponse": { "type": "object", "properties": { "invitations": { "type": "array", "items": { "$ref": "#/components/schemas/PendingInvitation" } }, "count": { "type": "integer" } }, "required": [ "invitations", "count" ] }, "Invitation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "email": { "type": "string", "format": "email" }, "role": { "type": "string", "enum": [ "ADMIN", "MEMBER", "VIEWER" ], "description": "Role assigned to the invited user" }, "status": { "type": "string", "enum": [ "PENDING", "ACCEPTED", "EXPIRED" ], "description": "Status of the invitation" }, "invitedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "invitedByUserId": { "type": "string", "nullable": true }, "workspace": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "logo": { "type": "string", "nullable": true } }, "required": [ "id", "name", "slug", "logo" ] } }, "required": [ "id", "email", "role", "status", "invitedAt", "invitedByUserId", "workspace" ] }, "SendInviteResponse": { "type": "object", "properties": { "invitation": { "$ref": "#/components/schemas/Invitation" }, "message": { "type": "string" } }, "required": [ "invitation", "message" ] }, "SendInviteRequest": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the person to invite", "example": "colleague@example.com" }, "role": { "type": "string", "enum": [ "ADMIN", "MEMBER", "VIEWER" ], "default": "MEMBER", "description": "Role assigned to the invited user" }, "workspaceId": { "type": "string", "minLength": 1, "description": "ID of the workspace to invite to" } }, "required": [ "email", "workspaceId" ] }, "GetInvitationResponse": { "type": "object", "properties": { "invitation": { "$ref": "#/components/schemas/Invitation" }, "status": { "type": "string", "enum": [ "PENDING" ] } }, "required": [ "invitation", "status" ] }, "GetAcceptedInvitationResponse": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "ACCEPTED" ] }, "message": { "type": "string" }, "workspace": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "logo": { "type": "string", "nullable": true } }, "required": [ "id", "name", "slug", "logo" ] } }, "required": [ "status", "message", "workspace" ] }, "GetExpiredInvitationResponse": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "EXPIRED" ] }, "message": { "type": "string" }, "workspace": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "logo": { "type": "string", "nullable": true } }, "required": [ "id", "name", "slug", "logo" ] } }, "required": [ "status", "message", "workspace" ] }, "AcceptInviteResponse": { "type": "object", "properties": { "membership": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "workspace": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" } }, "required": [ "id", "name", "slug" ] }, "role": { "type": "string", "enum": [ "ADMIN", "MEMBER", "VIEWER" ], "description": "Role assigned to the invited user" }, "acceptedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "workspaceId", "workspace", "role", "acceptedAt" ] }, "message": { "type": "string" } }, "required": [ "membership", "message" ] }, "RevokeInviteResponse": { "type": "object", "properties": { "message": { "type": "string" }, "action": { "type": "string", "enum": [ "declined", "revoked" ] } }, "required": [ "message", "action" ] }, "OrgInvitation": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "email": { "type": "string", "format": "email" }, "role": { "type": "string", "enum": [ "ADMIN", "MEMBER", "VIEWER" ], "description": "Role assigned to the invited user" }, "invitedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "invitedBy": { "type": "object", "nullable": true, "properties": { "id": { "type": "string" }, "name": { "type": "string", "nullable": true }, "email": { "type": "string" } }, "required": [ "id", "name", "email" ] } }, "required": [ "id", "email", "role", "invitedAt", "invitedBy" ] }, "ListOrgInvitationsResponse": { "type": "object", "properties": { "invitations": { "type": "array", "items": { "$ref": "#/components/schemas/OrgInvitation" } }, "count": { "type": "integer" } }, "required": [ "invitations", "count" ] }, "PlatformCapability": { "type": "object", "properties": { "maxChars": { "type": "integer" }, "supportsMedia": { "type": "boolean" }, "maxMediaCount": { "type": "integer" }, "supportsScheduling": { "type": "boolean" }, "supportsFirstComment": { "type": "boolean" }, "supportsThreads": { "type": "boolean" }, "supportedMediaTypes": { "type": "array", "items": { "type": "string", "enum": [ "image", "video", "gif" ] } }, "maxVideoDuration": { "type": "integer", "nullable": true }, "maxVideoSize": { "type": "integer", "nullable": true }, "maxImageSize": { "type": "integer", "nullable": true } }, "required": [ "maxChars", "supportsMedia", "maxMediaCount", "supportsScheduling", "supportsFirstComment", "supportsThreads", "supportedMediaTypes", "maxVideoDuration", "maxVideoSize", "maxImageSize" ] }, "PlatformInfo": { "type": "object", "properties": { "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] }, "name": { "type": "string" }, "icon": { "type": "string" }, "color": { "type": "string" }, "capabilities": { "$ref": "#/components/schemas/PlatformCapability" } }, "required": [ "platform", "name", "icon", "color", "capabilities" ] }, "PlatformListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PlatformInfo" } } }, "required": [ "data" ] }, "PlatformCapabilitiesResponse": { "type": "object", "additionalProperties": { "type": "object", "properties": { "maxChars": { "type": "integer" }, "maxMedia": { "type": "integer" }, "maxMediaSizeMB": { "type": "number" }, "maxVideoDurationSeconds": { "type": "number", "nullable": true }, "supports": { "type": "object", "properties": { "links": { "type": "boolean" }, "hashtags": { "type": "boolean" }, "mentions": { "type": "boolean" }, "firstComment": { "type": "boolean" }, "scheduling": { "type": "boolean" }, "threads": { "type": "boolean" } }, "required": [ "links", "hashtags", "mentions", "firstComment", "scheduling", "threads" ] }, "limits": { "type": "object", "properties": { "hashtags": { "type": "integer", "nullable": true }, "mentions": { "type": "integer", "nullable": true } }, "required": [ "hashtags", "mentions" ] } }, "required": [ "maxChars", "maxMedia", "maxMediaSizeMB", "maxVideoDurationSeconds", "supports", "limits" ] } }, "PlatformSpecificCapability": { "type": "object", "properties": { "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] }, "maxChars": { "type": "integer" }, "maxMedia": { "type": "integer" }, "maxMediaSizeMB": { "type": "number" }, "maxVideoDurationSeconds": { "type": "number", "nullable": true }, "supports": { "type": "object", "properties": { "links": { "type": "boolean" }, "hashtags": { "type": "boolean" }, "mentions": { "type": "boolean" }, "firstComment": { "type": "boolean" }, "scheduling": { "type": "boolean" }, "threads": { "type": "boolean" } }, "required": [ "links", "hashtags", "mentions", "firstComment", "scheduling", "threads" ] }, "limits": { "type": "object", "properties": { "hashtags": { "type": "integer", "nullable": true }, "mentions": { "type": "integer", "nullable": true } }, "required": [ "hashtags", "mentions" ] } }, "required": [ "platform", "maxChars", "maxMedia", "maxMediaSizeMB", "maxVideoDurationSeconds", "supports", "limits" ] }, "ManagedOAuthInfo": { "type": "object", "properties": { "available": { "type": "boolean" }, "displayName": { "type": "string" }, "scopes": { "type": "array", "items": { "type": "string" } }, "source": { "type": "string", "enum": [ "managed-oauth", "platform-config" ] } }, "required": [ "available" ] }, "ManagedOAuthResponse": { "type": "object", "properties": { "platforms": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/ManagedOAuthInfo" } } }, "required": [ "platforms" ] }, "PlatformDetailResponse": { "type": "object", "properties": { "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] }, "name": { "type": "string" }, "icon": { "type": "string" }, "color": { "type": "string" }, "capabilities": { "$ref": "#/components/schemas/PlatformCapability" } }, "required": [ "platform", "name", "icon", "color", "capabilities" ] }, "PlatformManagedOAuthResponse": { "type": "object", "properties": { "available": { "type": "boolean" }, "platform": { "type": "string" }, "displayName": { "type": "string" }, "description": { "type": "string" }, "scopes": { "type": "array", "items": { "type": "string" } }, "rateLimitTotal": { "type": "integer", "nullable": true }, "rateLimitRemaining": { "type": "integer", "nullable": true } }, "required": [ "available", "platform", "rateLimitTotal", "rateLimitRemaining" ] }, "TimeSlot": { "type": "object", "properties": { "day": { "type": "string", "enum": [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday" ], "description": "Day of the week" }, "hour": { "type": "integer", "minimum": 0, "maximum": 23, "description": "Hour (0-23)", "example": 9 }, "minute": { "type": "integer", "minimum": 0, "maximum": 59, "default": 0, "description": "Minute (0-59)", "example": 0 }, "enabled": { "type": "boolean", "default": true } }, "required": [ "day", "hour" ] }, "UpcomingPost": { "type": "object", "properties": { "datetime": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "day": { "type": "string" }, "hour": { "type": "integer" }, "minute": { "type": "integer" }, "postId": { "type": "string", "nullable": true }, "postContent": { "type": "string", "nullable": true, "description": "First 100 chars of post content" } }, "required": [ "datetime", "day", "hour", "minute", "postId", "postContent" ] }, "QueueStats": { "type": "object", "properties": { "scheduledPosts": { "type": "integer" }, "availableSlots": { "type": "integer" } }, "required": [ "scheduledPosts", "availableSlots" ] }, "QueuePreviewResponse": { "type": "object", "properties": { "accountId": { "type": "string" }, "platform": { "type": "string" }, "accountName": { "type": "string" }, "timezone": { "type": "string" }, "config": { "type": "object", "properties": { "slots": { "type": "array", "items": { "$ref": "#/components/schemas/TimeSlot" } }, "totalSlotsPerWeek": { "type": "integer" } }, "required": [ "slots", "totalSlotsPerWeek" ] }, "upcoming": { "type": "array", "items": { "$ref": "#/components/schemas/UpcomingPost" } }, "stats": { "$ref": "#/components/schemas/QueueStats" } }, "required": [ "accountId", "platform", "accountName", "timezone", "config", "upcoming", "stats" ] }, "QueueConfig": { "type": "object", "properties": { "slots": { "type": "array", "items": { "$ref": "#/components/schemas/TimeSlot" }, "description": "Time slots for automatic posting" }, "timezone": { "type": "string", "description": "IANA timezone (e.g., America/New_York)", "example": "America/New_York" } }, "required": [ "slots" ] }, "QueueSlotConfig": { "type": "object", "properties": { "slots": { "type": "array", "items": { "$ref": "#/components/schemas/TimeSlot" }, "minItems": 0, "maxItems": 50 }, "timezone": { "type": "string" } }, "required": [ "slots" ] }, "ReorderQueueRequest": { "type": "object", "properties": { "reorders": { "type": "array", "items": { "type": "object", "properties": { "postId": { "type": "string", "minLength": 1 }, "newPosition": { "type": "integer", "minimum": 1 } }, "required": [ "postId", "newPosition" ] }, "minItems": 1, "maxItems": 100, "description": "Array of post reordering instructions" } }, "required": [ "reorders" ] }, "UserProfileResponse": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "email": { "type": "string", "format": "email" }, "name": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true, "format": "uri" }, "externalId": { "type": "string", "nullable": true }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "workspaces": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "logoUrl": { "type": "string", "nullable": true }, "plan": { "type": "string" }, "role": { "type": "string" }, "joinedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "name", "slug", "logoUrl", "plan", "role", "joinedAt" ] } } }, "required": [ "id", "email", "name", "avatarUrl", "externalId", "createdAt", "updatedAt", "workspaces" ] }, "UpdateProfileRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100, "description": "User display name", "example": "John Doe" }, "avatarUrl": { "type": "string", "nullable": true, "maxLength": 500, "format": "uri", "description": "URL to user avatar image" } } }, "DeleteAccountResponse": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] }, "message": { "type": "string" } }, "required": [ "success", "message" ] }, "UserWorkspace": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "logo": { "type": "string", "nullable": true }, "logoUrl": { "type": "string", "nullable": true }, "plan": { "type": "string" }, "role": { "type": "string" }, "joinedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "memberCount": { "type": "integer" }, "accountCount": { "type": "integer" }, "postCount": { "type": "integer" } }, "required": [ "id", "name", "slug", "logo", "logoUrl", "plan", "role", "joinedAt", "memberCount", "accountCount", "postCount" ] }, "UserWorkspaceListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/UserWorkspace" } }, "total": { "type": "integer" } }, "required": [ "data", "total" ] }, "CreatedWorkspaceResponse": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "logo": { "type": "string", "nullable": true }, "plan": { "type": "string" }, "role": { "type": "string" }, "memberCount": { "type": "integer" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "name", "slug", "logo", "plan", "role", "memberCount", "createdAt" ] }, "MemberListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "allOf": [ { "$ref": "#/components/schemas/WorkspaceMember" }, { "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "userId": { "type": "string" }, "email": { "type": "string", "format": "email" }, "name": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true, "format": "uri" }, "role": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ], "description": "Member role in the workspace" }, "joinedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "invitationStatus": { "type": "string", "enum": [ "PENDING", "ACCEPTED" ] } }, "required": [ "id", "userId", "email", "name", "avatarUrl", "role", "joinedAt" ] } ] } } }, "required": [ "data" ] }, "MemberResponse": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "userId": { "type": "string" }, "email": { "type": "string", "format": "email" }, "name": { "type": "string", "nullable": true }, "role": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ], "description": "Member role in the workspace" }, "joinedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "email", "name", "role", "joinedAt" ] }, "UpdateRoleRequest": { "type": "object", "properties": { "role": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ], "description": "Member role in the workspace" } }, "required": [ "role" ] }, "RemoveMemberResponse": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] }, "Contact": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "workspaceId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] }, "platformId": { "type": "string", "description": "Platform-specific user ID for this contact" }, "socialAccountId": { "type": "string", "nullable": true, "description": "ID of the connected account this contact was seen through" }, "displayName": { "type": "string", "nullable": true }, "username": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true }, "tags": { "type": "array", "items": { "type": "string" }, "description": "Freeform tags used for broadcast segmentation", "example": [ "vip", "newsletter" ] }, "customFields": { "type": "object", "additionalProperties": { "nullable": true }, "description": "Arbitrary key/value metadata stored against the contact" }, "lastSeenAt": { "type": "string", "nullable": true, "format": "date-time", "description": "Last time any inbound platform event was seen for this contact", "example": "2024-02-26T12:00:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "socialAccount": { "type": "object", "nullable": true, "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "displayName": { "type": "string", "nullable": true }, "username": { "type": "string", "nullable": true }, "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] } }, "required": [ "id", "displayName", "username", "platform" ], "description": "The connected social account this contact was most recently seen through" }, "lastInboundAt": { "type": "string", "nullable": true, "format": "date-time", "description": "Most recent validated inbound Messenger event, if any", "example": "2024-02-26T12:00:00.000Z" }, "messengerEligibleUntil": { "type": "string", "nullable": true, "format": "date-time", "description": "FACEBOOK only. End of Meta's 24-hour messaging window. Null when the window has lapsed or does not apply to this platform.", "example": "2024-02-26T12:00:00.000Z" }, "isSuppressed": { "type": "boolean", "description": "Whether the contact has opted out of messaging" }, "suppressedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "suppressionReason": { "type": "string", "nullable": true, "description": "Why the contact was suppressed (e.g. STOP_KEYWORD, MANUAL)" }, "messagesSentCount": { "type": "integer", "description": "Total direct message deliveries recorded for this contact" }, "sequenceEnrollmentCount": { "type": "integer", "description": "Total sequence enrollments recorded for this contact" } }, "required": [ "id", "workspaceId", "platform", "platformId", "socialAccountId", "displayName", "username", "avatarUrl", "tags", "customFields", "lastSeenAt", "createdAt", "updatedAt", "socialAccount", "lastInboundAt", "messengerEligibleUntil", "isSuppressed", "suppressedAt", "suppressionReason", "messagesSentCount", "sequenceEnrollmentCount" ] }, "ContactListResponse": { "type": "object", "properties": { "contacts": { "type": "array", "items": { "$ref": "#/components/schemas/Contact" } }, "total": { "type": "integer" }, "page": { "type": "integer" }, "limit": { "type": "integer" }, "pages": { "type": "integer", "description": "Total number of pages" } }, "required": [ "contacts", "total", "page", "limit", "pages" ] }, "DeliveryStatus": { "type": "string", "enum": [ "PENDING", "DELIVERING", "DELIVERED", "FAILED", "READ" ], "description": "Delivery state of an outbound direct message" }, "ContactDelivery": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "status": { "$ref": "#/components/schemas/DeliveryStatus" }, "sentAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "readAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "errorCode": { "type": "string", "nullable": true }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "broadcast": { "type": "object", "nullable": true, "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "name": { "type": "string" } }, "required": [ "id", "name" ], "description": "Broadcast this delivery belonged to, or null for a one-off DM" } }, "required": [ "id", "status", "sentAt", "readAt", "errorCode", "createdAt", "broadcast" ] }, "EnrollmentStatus": { "type": "string", "enum": [ "ACTIVE", "COMPLETED", "EXITED", "FAILED" ], "description": "State of a contact's enrollment in a DM sequence" }, "ContactSequenceEnrollment": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "status": { "$ref": "#/components/schemas/EnrollmentStatus" }, "currentStep": { "type": "integer" }, "enrolledAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "exitedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "exitReason": { "type": "string", "nullable": true }, "sequence": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "name": { "type": "string" } }, "required": [ "id", "name" ] } }, "required": [ "id", "status", "currentStep", "enrolledAt", "exitedAt", "exitReason", "sequence" ] }, "ContactDetail": { "allOf": [ { "$ref": "#/components/schemas/Contact" }, { "type": "object", "properties": { "deliveries": { "type": "array", "items": { "$ref": "#/components/schemas/ContactDelivery" }, "description": "Up to 20 most recent deliveries, newest first" }, "sequenceEnrollments": { "type": "array", "items": { "$ref": "#/components/schemas/ContactSequenceEnrollment" }, "description": "Up to 10 most recent sequence enrollments, newest first" } }, "required": [ "deliveries", "sequenceEnrollments" ] } ] }, "ContactResponse": { "type": "object", "properties": { "contact": { "$ref": "#/components/schemas/ContactDetail" } }, "required": [ "contact" ] }, "CreateContactRequest": { "type": "object", "properties": { "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] }, "platformId": { "type": "string", "minLength": 1, "description": "Platform-specific user ID. Upserted on (workspace, platform, platformId)." }, "displayName": { "type": "string", "maxLength": 255 }, "username": { "type": "string", "maxLength": 255 }, "avatarUrl": { "type": "string", "format": "uri" }, "tags": { "type": "array", "items": { "type": "string", "maxLength": 100 }, "default": [] }, "customFields": { "type": "object", "additionalProperties": { "nullable": true }, "default": {} } }, "required": [ "platform", "platformId" ] }, "UpdateContactRequest": { "type": "object", "properties": { "displayName": { "type": "string", "nullable": true, "maxLength": 255 }, "tags": { "type": "array", "items": { "type": "string", "maxLength": 100 } }, "customFields": { "type": "object", "additionalProperties": { "nullable": true } } } }, "AddContactTagRequest": { "type": "object", "properties": { "tag": { "type": "string", "minLength": 1, "maxLength": 100 } }, "required": [ "tag" ] }, "SendContactMessageResponse": { "type": "object", "properties": { "delivery": { "type": "object", "properties": { "deliveryId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "status": { "$ref": "#/components/schemas/DeliveryStatus" }, "errorCode": { "type": "string", "description": "Present when the platform rejected the send (e.g. RATE_LIMITED, TOKEN_EXPIRED, OUTSIDE_WINDOW)" } }, "required": [ "deliveryId", "status" ] }, "contact": { "$ref": "#/components/schemas/ContactDetail" } }, "required": [ "delivery", "contact" ] }, "SendContactMessageRequest": { "type": "object", "properties": { "text": { "type": "string", "minLength": 1, "maxLength": 2000, "description": "Message body. 2,000 characters is Meta's Send API text limit.", "example": "Thanks for reaching out — here is the link you asked for." } }, "required": [ "text" ] }, "BroadcastSegmentRules": { "type": "object", "properties": { "tags": { "type": "array", "items": { "type": "string" }, "description": "Only contacts carrying at least one of these tags" }, "platforms": { "type": "array", "items": { "type": "string" }, "description": "Intersected with the broadcast's own platforms at send time" }, "hasInteraction": { "type": "boolean", "description": "Advisory only. The opt-in gate (contact must have prior inbound interaction) is always enforced server-side regardless of this value." } } }, "BroadcastStatus": { "type": "string", "enum": [ "DRAFT", "SCHEDULED", "SENDING", "SENT", "PAUSED", "FAILED" ], "description": "Lifecycle state of a broadcast" }, "Broadcast": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "workspaceId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "socialAccountId": { "type": "string", "nullable": true, "description": "Connected account the broadcast sends from" }, "name": { "type": "string" }, "messageTemplate": { "type": "string", "description": "Message body sent to each eligible contact" }, "platforms": { "type": "array", "items": { "type": "string" }, "description": "Platforms this broadcast targets", "example": [ "FACEBOOK" ] }, "segmentRules": { "$ref": "#/components/schemas/BroadcastSegmentRules" }, "scheduledFor": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "sentAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "status": { "$ref": "#/components/schemas/BroadcastStatus" }, "totalContacts": { "type": "integer", "description": "Number of contacts resolved when the broadcast was sent" }, "deliveredCount": { "type": "integer" }, "failedCount": { "type": "integer" }, "readCount": { "type": "integer" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "workspaceId", "socialAccountId", "name", "messageTemplate", "platforms", "segmentRules", "scheduledFor", "sentAt", "status", "totalContacts", "deliveredCount", "failedCount", "readCount", "createdAt", "updatedAt" ] }, "BroadcastPagination": { "type": "object", "properties": { "page": { "type": "integer" }, "limit": { "type": "integer" }, "total": { "type": "integer" }, "totalPages": { "type": "integer" } }, "required": [ "page", "limit", "total", "totalPages" ] }, "BroadcastListResponse": { "type": "object", "properties": { "broadcasts": { "type": "array", "items": { "$ref": "#/components/schemas/Broadcast" } }, "pagination": { "$ref": "#/components/schemas/BroadcastPagination" } }, "required": [ "broadcasts", "pagination" ] }, "BroadcastResponse": { "type": "object", "properties": { "broadcast": { "$ref": "#/components/schemas/Broadcast" } }, "required": [ "broadcast" ] }, "CreateBroadcastRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255 }, "messageTemplate": { "type": "string", "minLength": 1, "maxLength": 1000 }, "platforms": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "At least one platform is required", "example": [ "FACEBOOK" ] }, "socialAccountId": { "type": "string", "description": "Connected account to send from. Must belong to this workspace and its platform must be one of `platforms`." }, "segmentRules": { "allOf": [ { "$ref": "#/components/schemas/BroadcastSegmentRules" }, { "default": {} } ] }, "scheduledFor": { "type": "string", "format": "date-time" } }, "required": [ "name", "messageTemplate", "platforms" ] }, "BroadcastPreviewCountResponse": { "type": "object", "properties": { "count": { "type": "integer", "description": "Number of contacts currently eligible for this selection" } }, "required": [ "count" ] }, "BroadcastPreviewCountRequest": { "type": "object", "properties": { "platforms": { "type": "array", "items": { "type": "string" } }, "socialAccountId": { "type": "string" }, "tags": { "type": "array", "items": { "type": "string" } } } }, "BroadcastDetailResponse": { "type": "object", "properties": { "broadcast": { "$ref": "#/components/schemas/Broadcast" }, "deliveryStats": { "type": "object", "additionalProperties": { "type": "integer" }, "description": "Delivery counts keyed by DeliveryStatus", "example": { "DELIVERED": 128, "FAILED": 3 } } }, "required": [ "broadcast", "deliveryStats" ] }, "UpdateBroadcastRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255 }, "messageTemplate": { "type": "string", "minLength": 1, "maxLength": 1000 }, "platforms": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "socialAccountId": { "type": "string", "nullable": true }, "segmentRules": { "$ref": "#/components/schemas/BroadcastSegmentRules" }, "scheduledFor": { "type": "string", "nullable": true, "format": "date-time" } } }, "RetryBroadcastResponse": { "type": "object", "properties": { "broadcast": { "$ref": "#/components/schemas/Broadcast" }, "retriedContacts": { "type": "integer" }, "batches": { "type": "integer" } }, "required": [ "broadcast", "retriedContacts", "batches" ] }, "SendBroadcastResponse": { "type": "object", "properties": { "broadcast": { "$ref": "#/components/schemas/Broadcast" }, "enqueuedContacts": { "type": "integer" }, "batches": { "type": "integer", "description": "Number of queue batches enqueued (50 contacts per batch)" } }, "required": [ "broadcast", "enqueuedContacts", "batches" ] }, "BroadcastDelivery": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "broadcastId": { "type": "string", "nullable": true, "description": "Null for a one-off direct message sent outside a broadcast" }, "contactId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] }, "status": { "$ref": "#/components/schemas/DeliveryStatus" }, "sentAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "readAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "errorCode": { "type": "string", "nullable": true }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "contact": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "displayName": { "type": "string", "nullable": true }, "username": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true }, "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] } }, "required": [ "id", "displayName", "username", "avatarUrl", "platform" ] } }, "required": [ "id", "broadcastId", "contactId", "platform", "status", "sentAt", "readAt", "errorCode", "createdAt", "updatedAt", "contact" ] }, "BroadcastDeliveryListResponse": { "type": "object", "properties": { "deliveries": { "type": "array", "items": { "$ref": "#/components/schemas/BroadcastDelivery" } }, "pagination": { "$ref": "#/components/schemas/BroadcastPagination" } }, "required": [ "deliveries", "pagination" ] }, "SequenceStatus": { "type": "string", "enum": [ "DRAFT", "ACTIVE", "PAUSED", "ARCHIVED" ], "description": "Lifecycle state of a sequence. ARCHIVED is the soft-deleted state." }, "Sequence": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "workspaceId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "name": { "type": "string" }, "status": { "$ref": "#/components/schemas/SequenceStatus" }, "enrollmentRules": { "type": "object", "additionalProperties": { "nullable": true }, "description": "Freeform enrollment rule object" }, "exitOnReply": { "type": "boolean", "description": "Exit a contact from the sequence when they reply" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "workspaceId", "name", "status", "enrollmentRules", "exitOnReply", "createdAt", "updatedAt" ] }, "SequenceListItem": { "allOf": [ { "$ref": "#/components/schemas/Sequence" }, { "type": "object", "properties": { "_count": { "type": "object", "properties": { "steps": { "type": "integer" }, "enrollments": { "type": "integer", "description": "Count of ACTIVE enrollments only" } }, "required": [ "steps", "enrollments" ] } }, "required": [ "_count" ] } ] }, "SequencePagination": { "type": "object", "properties": { "page": { "type": "integer" }, "limit": { "type": "integer" }, "total": { "type": "integer" }, "totalPages": { "type": "integer" } }, "required": [ "page", "limit", "total", "totalPages" ] }, "SequenceListResponse": { "type": "object", "properties": { "sequences": { "type": "array", "items": { "$ref": "#/components/schemas/SequenceListItem" } }, "pagination": { "$ref": "#/components/schemas/SequencePagination" } }, "required": [ "sequences", "pagination" ] }, "SequenceResponse": { "type": "object", "properties": { "sequence": { "$ref": "#/components/schemas/Sequence" } }, "required": [ "sequence" ] }, "CreateSequenceRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255 }, "enrollmentRules": { "type": "object", "additionalProperties": { "nullable": true }, "default": {} }, "exitOnReply": { "type": "boolean", "default": true } }, "required": [ "name" ] }, "SequenceStep": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "sequenceId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "stepOrder": { "type": "integer", "description": "1-based position of this step within the sequence" }, "messageTemplate": { "type": "string" }, "delayHours": { "type": "integer", "description": "Hours to wait before this step is sent (0–8760)" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "sequenceId", "stepOrder", "messageTemplate", "delayHours", "createdAt", "updatedAt" ] }, "SequenceDetail": { "allOf": [ { "$ref": "#/components/schemas/Sequence" }, { "type": "object", "properties": { "steps": { "type": "array", "items": { "$ref": "#/components/schemas/SequenceStep" }, "description": "All steps, ordered by stepOrder ascending" }, "_count": { "type": "object", "properties": { "enrollments": { "type": "integer", "description": "Total enrollments across all statuses" } }, "required": [ "enrollments" ] } }, "required": [ "steps", "_count" ] } ] }, "SequenceDetailResponse": { "type": "object", "properties": { "sequence": { "$ref": "#/components/schemas/SequenceDetail" }, "enrollmentStats": { "type": "object", "additionalProperties": { "type": "integer" }, "description": "Enrollment counts keyed by EnrollmentStatus", "example": { "ACTIVE": 42, "COMPLETED": 8 } } }, "required": [ "sequence", "enrollmentStats" ] }, "UpdateSequenceRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255 }, "status": { "$ref": "#/components/schemas/SequenceStatus" }, "exitOnReply": { "type": "boolean" } } }, "SequenceStepListResponse": { "type": "object", "properties": { "steps": { "type": "array", "items": { "$ref": "#/components/schemas/SequenceStep" } } }, "required": [ "steps" ] }, "SequenceStepResponse": { "type": "object", "properties": { "step": { "$ref": "#/components/schemas/SequenceStep" } }, "required": [ "step" ] }, "CreateSequenceStepRequest": { "type": "object", "properties": { "messageTemplate": { "type": "string", "minLength": 1, "maxLength": 2000 }, "delayHours": { "type": "integer", "minimum": 0, "maximum": 8760, "description": "Hours to wait before sending this step. Max 8760 (one year)." }, "stepOrder": { "type": "integer", "minimum": 1, "description": "Position in the sequence. Appended at the end when omitted." } }, "required": [ "messageTemplate", "delayHours" ] }, "UpdateSequenceStepRequest": { "type": "object", "properties": { "messageTemplate": { "type": "string", "minLength": 1, "maxLength": 2000 }, "delayHours": { "type": "integer", "minimum": 0, "maximum": 8760 }, "stepOrder": { "type": "integer", "minimum": 1 } } }, "SequenceEnrollment": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "sequenceId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "contactId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "workspaceId": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "platform": { "type": "string", "description": "Platform the sequence messages are delivered on", "example": "FACEBOOK" }, "currentStep": { "type": "integer" }, "nextRunAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "enrolledAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "exitedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "exitReason": { "type": "string", "nullable": true }, "status": { "$ref": "#/components/schemas/EnrollmentStatus" } }, "required": [ "id", "sequenceId", "contactId", "workspaceId", "platform", "currentStep", "nextRunAt", "enrolledAt", "exitedAt", "exitReason", "status" ] }, "SequenceEnrollmentWithContact": { "allOf": [ { "$ref": "#/components/schemas/SequenceEnrollment" }, { "type": "object", "properties": { "contact": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "displayName": { "type": "string", "nullable": true }, "username": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true }, "platform": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Social media platform" } ] } }, "required": [ "id", "displayName", "username", "avatarUrl", "platform" ] } }, "required": [ "contact" ] } ] }, "SequenceEnrollmentListResponse": { "type": "object", "properties": { "enrollments": { "type": "array", "items": { "$ref": "#/components/schemas/SequenceEnrollmentWithContact" } }, "pagination": { "$ref": "#/components/schemas/SequencePagination" } }, "required": [ "enrollments", "pagination" ] }, "SequenceEnrollmentResponse": { "type": "object", "properties": { "enrollment": { "$ref": "#/components/schemas/SequenceEnrollment" } }, "required": [ "enrollment" ] }, "EnrollContactRequest": { "type": "object", "properties": { "contactId": { "type": "string", "minLength": 1 }, "platform": { "type": "string", "minLength": 1, "example": "FACEBOOK" } }, "required": [ "contactId", "platform" ] }, "ApiKey": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "name": { "type": "string", "description": "Human-readable name for the API key", "example": "Production Key" }, "prefix": { "type": "string", "description": "First 12 characters of the key (for identification)", "example": "vb_live_abc1" }, "scopes": { "type": "array", "items": { "type": "string" }, "description": "Granted permission scopes", "example": [ "posts:write", "accounts:read" ] }, "allowedIps": { "type": "array", "nullable": true, "items": { "type": "string" }, "description": "IP allowlist (CIDR notation supported). Null means all IPs allowed.", "example": [ "192.168.1.0/24" ] }, "lastUsedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "Last time this key was used to authenticate a request", "example": "2024-02-26T12:00:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "expiresAt": { "type": "string", "nullable": true, "format": "date-time", "description": "When this key expires. Null means no expiration.", "example": "2024-02-26T12:00:00.000Z" }, "expirationStatus": { "type": "string", "enum": [ "active", "expiring_soon", "expired" ], "description": "Computed expiration status: active, expiring_soon (within 7 days), or expired" }, "daysUntilExpiration": { "type": "integer", "nullable": true, "description": "Days until expiration. Null if no expiration set.", "example": 14 } }, "required": [ "id", "name", "prefix", "scopes", "allowedIps", "lastUsedAt", "createdAt", "expiresAt", "expirationStatus", "daysUntilExpiration" ] }, "CreateApiKeyResponse": { "type": "object", "properties": { "data": { "allOf": [ { "$ref": "#/components/schemas/ApiKey" }, { "type": "object", "properties": { "key": { "type": "string", "description": "The full API key. Only returned once on creation — store it securely.", "example": "vb_live_abc123def456ghi789..." } }, "required": [ "key" ] } ] } }, "required": [ "data" ] }, "CreateApiKeyRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Human-readable name for the key", "example": "CI/CD Pipeline Key" }, "scopes": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "At least one permission scope, or * for explicit unrestricted workspace access" }, "expiresAt": { "type": "string", "nullable": true, "format": "date-time", "description": "Optional expiration date (ISO 8601)", "example": "2025-06-01T00:00:00.000Z" } }, "required": [ "name", "scopes" ] }, "ExpiringKeysResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ApiKey" } }, "meta": { "type": "object", "properties": { "withinDays": { "type": "integer", "description": "The number of days used for the expiration window", "example": 7 }, "total": { "type": "integer", "description": "Total number of keys expiring within the window", "example": 2 } }, "required": [ "withinDays", "total" ] } }, "required": [ "data", "meta" ] }, "PlatformStatusDetail": { "type": "object", "properties": { "platform": { "type": "string", "description": "Platform identifier (lowercase)", "example": "twitter" }, "status": { "type": "string", "enum": [ "operational", "degraded", "down" ], "description": "Platform operational status level" }, "lastSuccessfulPublish": { "type": "string", "nullable": true, "format": "date-time", "description": "Timestamp of the last successful publish for this platform", "example": "2024-02-26T12:00:00.000Z" }, "errorRateLastHour": { "type": "integer", "minimum": 0, "maximum": 100, "description": "Error rate in the last hour as a percentage (0-100)", "example": 5 }, "totalPublishesLastHour": { "type": "integer", "description": "Total publish attempts in the last hour", "example": 42 }, "checkedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "platform", "status", "lastSuccessfulPublish", "errorRateLastHour", "totalPublishesLastHour", "checkedAt" ] }, "PlatformStatusResponse": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "operational", "degraded", "down" ], "description": "Overall status across all platforms" }, "timestamp": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "platforms": { "type": "array", "items": { "$ref": "#/components/schemas/PlatformStatusDetail" } } }, "required": [ "status", "timestamp", "platforms" ] }, "PlatformStatusDetailed": { "type": "object", "properties": { "platform": { "type": "string" }, "status": { "type": "string", "enum": [ "operational", "degraded", "down" ], "description": "Platform operational status level" }, "lastSuccessfulPublish": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "errorRateLastHour": { "type": "integer" }, "totalPublishesLastHour": { "type": "integer" }, "successCountLastHour": { "type": "integer" }, "failCountLastHour": { "type": "integer" }, "checkedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "platform", "status", "lastSuccessfulPublish", "errorRateLastHour", "totalPublishesLastHour", "successCountLastHour", "failCountLastHour", "checkedAt" ] }, "AISettings": { "type": "object", "nullable": true, "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "provider": { "type": "string" }, "model": { "type": "string", "nullable": true }, "baseUrl": { "type": "string", "nullable": true, "format": "uri" }, "defaultStyle": { "type": "string", "nullable": true, "enum": [ "professional", "casual", "engaging", "formal", "humorous" ], "description": "Default writing style for AI-generated content" }, "enabled": { "type": "boolean" }, "apiKeyConfigured": { "type": "boolean" }, "apiKeyHint": { "type": "string", "nullable": true }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "provider", "model", "baseUrl", "defaultStyle", "enabled", "apiKeyConfigured", "apiKeyHint", "createdAt", "updatedAt" ] }, "AISettingsResponse": { "type": "object", "properties": { "configured": { "type": "boolean" }, "settings": { "$ref": "#/components/schemas/AISettings" } }, "required": [ "configured", "settings" ] }, "CreateAISettingsRequest": { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "OPENAI", "ANTHROPIC", "GOOGLE" ], "description": "AI provider" }, "apiKey": { "type": "string", "minLength": 1, "maxLength": 500, "description": "API key for the AI provider" }, "model": { "type": "string", "maxLength": 100, "description": "Specific model to use (optional)" }, "baseUrl": { "type": "string", "format": "uri", "description": "Custom base URL for API (optional)" }, "defaultStyle": { "type": "string", "enum": [ "professional", "casual", "engaging", "formal", "humorous" ], "description": "Default writing style for AI-generated content" }, "enabled": { "type": "boolean", "default": true } }, "required": [ "provider", "apiKey" ] }, "UpdateAISettingsRequest": { "type": "object", "properties": { "provider": { "type": "string", "enum": [ "OPENAI", "ANTHROPIC", "GOOGLE" ], "description": "AI provider" }, "apiKey": { "type": "string", "minLength": 1, "maxLength": 500 }, "model": { "type": "string", "nullable": true, "maxLength": 100 }, "baseUrl": { "type": "string", "nullable": true, "format": "uri" }, "defaultStyle": { "type": "string", "nullable": true, "enum": [ "professional", "casual", "engaging", "formal", "humorous" ], "description": "Default writing style for AI-generated content" }, "enabled": { "type": "boolean" } } }, "TestConnectionResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "provider": { "type": "string" }, "error": { "type": "string" } }, "required": [ "success", "message" ] }, "AIModel": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "recommended": { "type": "boolean" } }, "required": [ "id", "name" ] }, "AIProviderInfo": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "models": { "type": "array", "items": { "$ref": "#/components/schemas/AIModel" } }, "requiresApiKey": { "type": "boolean" }, "keyPrefix": { "type": "string" } }, "required": [ "id", "name", "models", "requiresApiKey", "keyPrefix" ] }, "AIProvidersResponse": { "type": "object", "properties": { "providers": { "type": "array", "items": { "$ref": "#/components/schemas/AIProviderInfo" } } }, "required": [ "providers" ] }, "AIProviderConfigsResponse": { "type": "object", "properties": { "contentEnhancement": { "type": "object", "nullable": true, "properties": { "primaryProvider": { "type": "string" }, "primaryModel": { "type": "string" }, "backupProvider": { "type": "string", "nullable": true }, "backupModel": { "type": "string", "nullable": true }, "updatedAt": { "type": "string" } }, "required": [ "primaryProvider", "primaryModel", "backupProvider", "backupModel", "updatedAt" ] }, "imageCreation": { "type": "object", "nullable": true, "properties": { "primaryProvider": { "type": "string" }, "primaryModel": { "type": "string" }, "backupProvider": { "type": "string", "nullable": true }, "backupModel": { "type": "string", "nullable": true }, "updatedAt": { "type": "string" } }, "required": [ "primaryProvider", "primaryModel", "backupProvider", "backupModel", "updatedAt" ] } }, "required": [ "contentEnhancement", "imageCreation" ] }, "UpdateAIProviderConfigRequest": { "type": "object", "properties": { "feature": { "type": "string", "enum": [ "content_enhancement", "image_creation" ], "description": "AI feature type" }, "primaryProvider": { "type": "string", "enum": [ "openai", "anthropic", "google", "stability" ], "description": "AI provider for admin configuration" }, "primaryModel": { "type": "string", "minLength": 1, "maxLength": 200 }, "backupProvider": { "type": "string", "nullable": true, "enum": [ "openai", "anthropic", "google", "stability" ], "description": "AI provider for admin configuration" }, "backupModel": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 200 } }, "required": [ "feature", "primaryProvider", "primaryModel" ] }, "AIApiKey": { "type": "object", "properties": { "provider": { "type": "string" }, "maskedKey": { "type": "string" }, "lastTestedAt": { "type": "string", "nullable": true }, "isValid": { "type": "boolean" }, "updatedAt": { "type": "string" } }, "required": [ "provider", "maskedKey", "lastTestedAt", "isValid", "updatedAt" ] }, "AIApiKeysResponse": { "type": "object", "properties": { "keys": { "type": "array", "items": { "$ref": "#/components/schemas/AIApiKey" } } }, "required": [ "keys" ] }, "UpdateAIApiKeyRequest": { "type": "object", "properties": { "apiKey": { "type": "string", "minLength": 1, "maxLength": 500 } }, "required": [ "apiKey" ] }, "TestAIApiKeyResponse": { "type": "object", "properties": { "provider": { "type": "string" }, "success": { "type": "boolean" }, "modelsCount": { "type": "integer" }, "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" } }, "required": [ "code", "message" ] } }, "required": [ "provider", "success" ] }, "AdminAIModel": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" } }, "required": [ "id", "name" ] }, "AIModelListResponse": { "type": "object", "properties": { "provider": { "type": "string" }, "models": { "type": "array", "items": { "$ref": "#/components/schemas/AdminAIModel" } }, "source": { "type": "string", "enum": [ "live", "cache", "fallback" ] }, "notice": { "type": "string", "nullable": true } }, "required": [ "provider", "models", "source", "notice" ] }, "VersionOverride": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ] }, "overrideVersion": { "type": "string" }, "enabled": { "type": "boolean" }, "reason": { "type": "string" }, "expiresAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "createdBy": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "platform", "overrideVersion", "enabled", "reason", "expiresAt", "createdBy", "createdAt" ] }, "PlatformApiVersion": { "type": "object", "properties": { "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ] }, "currentVersion": { "type": "string" }, "minimumVersion": { "type": "string" }, "latestAvailable": { "type": "string", "nullable": true }, "versionStatus": { "type": "string", "enum": [ "HEALTHY", "WARNING", "CRITICAL", "STALE" ], "description": "Platform API version status" }, "deprecationDate": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "releaseNotes": { "type": "string", "nullable": true }, "updatedBy": { "type": "string", "nullable": true }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "overrides": { "type": "array", "items": { "$ref": "#/components/schemas/VersionOverride" } } }, "required": [ "platform", "currentVersion", "minimumVersion", "latestAvailable", "versionStatus", "deprecationDate", "releaseNotes", "updatedBy", "updatedAt" ] }, "PlatformVersionListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PlatformApiVersion" } } }, "required": [ "data" ] }, "VersionCheck": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ] }, "foundVersion": { "type": "string", "nullable": true }, "checkMethod": { "type": "string" }, "success": { "type": "boolean" }, "notes": { "type": "string", "nullable": true }, "checkedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "platform", "foundVersion", "checkMethod", "success", "notes", "checkedAt" ] }, "VersionAlert": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ] }, "alertType": { "type": "string" }, "severity": { "type": "string", "enum": [ "LOW", "MEDIUM", "HIGH", "CRITICAL" ] }, "message": { "type": "string" }, "acknowledgedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "acknowledgedBy": { "type": "string", "nullable": true }, "resolvedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "platform", "alertType", "severity", "message", "acknowledgedAt", "acknowledgedBy", "resolvedAt", "createdAt" ] }, "PlatformVersionDetailResponse": { "type": "object", "properties": { "data": { "type": "object", "properties": { "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ] }, "currentVersion": { "type": "string" }, "minimumVersion": { "type": "string" }, "latestAvailable": { "type": "string", "nullable": true }, "versionStatus": { "type": "string", "enum": [ "HEALTHY", "WARNING", "CRITICAL", "STALE" ], "description": "Platform API version status" }, "deprecationDate": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "releaseNotes": { "type": "string", "nullable": true }, "updatedBy": { "type": "string", "nullable": true }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "overrides": { "type": "array", "items": { "$ref": "#/components/schemas/VersionOverride" } }, "checks": { "type": "array", "items": { "$ref": "#/components/schemas/VersionCheck" } }, "alerts": { "type": "array", "items": { "$ref": "#/components/schemas/VersionAlert" } } }, "required": [ "platform", "currentVersion", "minimumVersion", "latestAvailable", "versionStatus", "deprecationDate", "releaseNotes", "updatedBy", "updatedAt", "checks", "alerts" ] } }, "required": [ "data" ] }, "UpdateVersionRequest": { "type": "object", "properties": { "currentVersion": { "type": "string", "minLength": 1, "maxLength": 50 }, "minimumVersion": { "type": "string", "minLength": 1, "maxLength": 50 }, "latestAvailable": { "type": "string", "nullable": true, "minLength": 1, "maxLength": 50 }, "versionStatus": { "type": "string", "enum": [ "HEALTHY", "WARNING", "CRITICAL", "STALE" ], "description": "Platform API version status" }, "deprecationDate": { "type": "string", "nullable": true, "format": "date-time" }, "releaseNotes": { "type": "string", "nullable": true, "maxLength": 2000 } } }, "ManualCheckRequest": { "type": "object", "properties": { "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ] }, "foundVersion": { "type": "string", "minLength": 1, "maxLength": 50 }, "notes": { "type": "string", "maxLength": 1000 }, "success": { "type": "boolean", "default": true } }, "required": [ "platform" ] }, "CreateOverrideRequest": { "type": "object", "properties": { "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ] }, "overrideVersion": { "type": "string", "minLength": 1, "maxLength": 50 }, "reason": { "type": "string", "minLength": 10, "maxLength": 1000 }, "expiresAt": { "type": "string", "nullable": true, "format": "date-time" } }, "required": [ "platform", "overrideVersion", "reason" ] }, "AlertListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/VersionAlert" } }, "total": { "type": "integer" } }, "required": [ "data", "total" ] }, "VersionDashboardResponse": { "type": "object", "properties": { "data": { "type": "object", "properties": { "totalPlatforms": { "type": "integer" }, "upToDate": { "type": "integer" }, "outdated": { "type": "integer" }, "activeAlerts": { "type": "integer" }, "statusBreakdown": { "type": "object", "properties": { "HEALTHY": { "type": "integer" }, "WARNING": { "type": "integer" }, "CRITICAL": { "type": "integer" }, "STALE": { "type": "integer" } }, "required": [ "HEALTHY", "WARNING", "CRITICAL", "STALE" ] }, "lastCheck": { "type": "object", "nullable": true, "properties": { "checkedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "method": { "type": "string" } }, "required": [ "checkedAt", "method" ] } }, "required": [ "totalPlatforms", "upToDate", "outdated", "activeAlerts", "statusBreakdown", "lastCheck" ] } }, "required": [ "data" ] }, "DetectorInfo": { "type": "object", "properties": { "platform": { "type": "string" }, "method": { "type": "string" }, "endpoint": { "type": "string" }, "description": { "type": "string" } }, "required": [ "platform", "method", "description" ] }, "DetectorListResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/DetectorInfo" } } }, "required": [ "data" ] }, "CleanupResults": { "type": "object", "properties": { "posts": { "type": "integer" }, "socialAccounts": { "type": "integer" }, "members": { "type": "integer" }, "workspaces": { "type": "integer" }, "users": { "type": "integer" } }, "required": [ "posts", "socialAccounts", "members", "workspaces", "users" ] }, "ClearTestDataResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "deleted": { "$ref": "#/components/schemas/CleanupResults" } }, "required": [ "success", "message", "deleted" ] }, "PlatformConfigListItem": { "type": "object", "properties": { "id": { "type": "string" }, "platformKey": { "type": "string" }, "name": { "type": "string" }, "shortName": { "type": "string" }, "icon": { "type": "string" }, "color": { "type": "string" }, "bgColor": { "type": "string" }, "isEnabled": { "type": "boolean" }, "isConfigured": { "type": "boolean" }, "isAvailable": { "type": "boolean" }, "authMethod": { "type": "string" }, "usesPKCE": { "type": "boolean" }, "tokenExpires": { "type": "boolean" }, "supportsRefresh": { "type": "boolean" }, "activeAccounts": { "type": "integer" }, "errorAccounts": { "type": "integer" }, "credentialsUpdatedAt": { "type": "string", "nullable": true }, "enabledAt": { "type": "string", "nullable": true }, "disabledAt": { "type": "string", "nullable": true }, "updatedAt": { "type": "string" }, "credentialPreview": { "nullable": true } }, "required": [ "id", "platformKey", "name", "shortName", "icon", "color", "bgColor", "isEnabled", "isConfigured", "isAvailable", "authMethod", "usesPKCE", "tokenExpires", "supportsRefresh", "activeAccounts", "errorAccounts", "credentialsUpdatedAt", "enabledAt", "disabledAt", "updatedAt" ] }, "PlatformConfigListResponse": { "type": "object", "properties": { "platforms": { "type": "array", "items": { "$ref": "#/components/schemas/PlatformConfigListItem" } }, "summary": { "type": "object", "properties": { "total": { "type": "integer" }, "enabled": { "type": "integer" }, "configured": { "type": "integer" } }, "required": [ "total", "enabled", "configured" ] } }, "required": [ "platforms", "summary" ] }, "PlatformConfigDetail": { "type": "object", "properties": { "id": { "type": "string" }, "platformKey": { "type": "string" }, "name": { "type": "string" }, "shortName": { "type": "string" }, "icon": { "type": "string" }, "color": { "type": "string" }, "bgColor": { "type": "string" }, "isEnabled": { "type": "boolean" }, "isConfigured": { "type": "boolean" }, "isAvailable": { "type": "boolean" }, "authMethod": { "type": "string", "enum": [ "OAUTH2", "OAUTH1", "API_KEY", "BASIC" ], "description": "Authentication method for the platform" }, "usesPKCE": { "type": "boolean" }, "tokenExpires": { "type": "boolean" }, "supportsRefresh": { "type": "boolean" }, "authorizationUrl": { "type": "string", "nullable": true }, "tokenUrl": { "type": "string", "nullable": true }, "defaultScopes": { "type": "array", "items": { "type": "string" } }, "capabilities": { "type": "object", "additionalProperties": { "nullable": true } }, "rateLimitRequests": { "type": "integer", "nullable": true }, "rateLimitWindowMs": { "type": "integer", "nullable": true }, "metadata": { "type": "object", "nullable": true, "additionalProperties": { "nullable": true } }, "notes": { "type": "string", "nullable": true }, "credentialsUpdatedAt": { "type": "string", "nullable": true }, "enabledAt": { "type": "string", "nullable": true }, "disabledAt": { "type": "string", "nullable": true }, "createdAt": { "type": "string" }, "updatedAt": { "type": "string" } }, "required": [ "id", "platformKey", "name", "shortName", "icon", "color", "bgColor", "isEnabled", "isConfigured", "isAvailable", "authMethod", "usesPKCE", "tokenExpires", "supportsRefresh", "authorizationUrl", "tokenUrl", "defaultScopes", "capabilities", "rateLimitRequests", "rateLimitWindowMs", "metadata", "notes", "credentialsUpdatedAt", "enabledAt", "disabledAt", "createdAt", "updatedAt" ] }, "PlatformConfigDetailResponse": { "type": "object", "properties": { "platform": { "$ref": "#/components/schemas/PlatformConfigDetail" }, "stats": { "type": "object", "properties": { "activeAccounts": { "type": "integer" }, "errorAccounts": { "type": "integer" }, "totalAccounts": { "type": "integer" } }, "required": [ "activeAccounts", "errorAccounts", "totalAccounts" ] }, "credentialStatus": { "type": "object", "properties": { "configured": { "type": "boolean" }, "lastUpdated": { "type": "string", "nullable": true }, "secretExists": { "type": "boolean" } }, "required": [ "configured", "lastUpdated", "secretExists" ] }, "requiredCredentialFields": { "type": "array", "items": { "type": "string" } } }, "required": [ "platform", "stats", "credentialStatus", "requiredCredentialFields" ] }, "UpdatePlatformResponse": { "type": "object", "properties": { "platform": { "type": "object", "properties": { "id": { "type": "string" }, "platformKey": { "type": "string" }, "name": { "type": "string" }, "shortName": { "type": "string" }, "isEnabled": { "type": "boolean" }, "isConfigured": { "type": "boolean" }, "updatedAt": { "type": "string" } }, "required": [ "id", "platformKey", "name", "shortName", "isEnabled", "isConfigured", "updatedAt" ] }, "success": { "type": "boolean" }, "message": { "type": "string" } }, "required": [ "platform", "success", "message" ] }, "UpdatePlatformConfigRequest": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "shortName": { "type": "string", "minLength": 1, "maxLength": 50 }, "icon": { "type": "string", "maxLength": 100 }, "color": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" }, "bgColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" }, "isAvailable": { "type": "boolean" }, "defaultScopes": { "type": "array", "items": { "type": "string" } }, "capabilities": { "type": "object", "additionalProperties": { "nullable": true } }, "rateLimitRequests": { "type": "integer", "nullable": true, "minimum": 0, "exclusiveMinimum": true }, "rateLimitWindowMs": { "type": "integer", "nullable": true, "minimum": 0, "exclusiveMinimum": true }, "metadata": { "type": "object", "additionalProperties": { "nullable": true } }, "notes": { "type": "string", "nullable": true, "maxLength": 1000 } } }, "EnableDisablePlatformRequest": { "type": "object", "properties": { "reason": { "type": "string", "maxLength": 500 } } }, "SetCredentialsResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "credentialsUpdatedAt": { "type": "string" }, "message": { "type": "string" } }, "required": [ "success", "credentialsUpdatedAt", "message" ] }, "PlatformCredentialsRequest": { "type": "object", "properties": { "clientId": { "type": "string" }, "clientSecret": { "type": "string" }, "appId": { "type": "string" }, "appSecret": { "type": "string" }, "clientKey": { "type": "string" }, "apiKey": { "type": "string" }, "webhookSecret": { "type": "string" }, "instanceUrl": { "type": "string", "format": "uri" }, "loginConfigId": { "type": "string" } } }, "TestCredentialsResponse": { "type": "object", "properties": { "success": { "type": "boolean" }, "message": { "type": "string" }, "error": { "type": "string" } }, "required": [ "success", "message" ] }, "PlatformAuditLogEntry": { "type": "object", "properties": { "id": { "type": "string" }, "action": { "type": "string" }, "actorEmail": { "type": "string", "nullable": true }, "actorType": { "type": "string" }, "changes": { "nullable": true }, "reason": { "type": "string", "nullable": true }, "createdAt": { "type": "string" } }, "required": [ "id", "action", "actorEmail", "actorType", "reason", "createdAt" ] }, "PlatformAuditLogResponse": { "type": "object", "properties": { "logs": { "type": "array", "items": { "$ref": "#/components/schemas/PlatformAuditLogEntry" } }, "total": { "type": "integer" }, "pagination": { "type": "object", "properties": { "limit": { "type": "integer" }, "offset": { "type": "integer" }, "hasMore": { "type": "boolean" } }, "required": [ "limit", "offset", "hasMore" ] } }, "required": [ "logs", "total", "pagination" ] }, "AnalyticsMetrics": { "type": "object", "properties": { "totalUsers": { "type": "integer" }, "totalOrgs": { "type": "integer" }, "totalPosts": { "type": "integer" }, "postsThisWeek": { "type": "integer" }, "postsThisMonth": { "type": "integer" }, "activeUsersDaily": { "type": "integer" }, "activeUsersWeekly": { "type": "integer" }, "activeUsersMonthly": { "type": "integer" } }, "required": [ "totalUsers", "totalOrgs", "totalPosts", "postsThisWeek", "postsThisMonth", "activeUsersDaily", "activeUsersWeekly", "activeUsersMonthly" ] }, "ActiveWorkspace": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "postsThisMonth": { "type": "integer" }, "members": { "type": "integer" }, "accounts": { "type": "integer" } }, "required": [ "id", "name", "postsThisMonth", "members", "accounts" ] }, "RevenueMetrics": { "type": "object", "properties": { "mrr": { "type": "integer" }, "arr": { "type": "integer" }, "totalSubscriptions": { "type": "integer" }, "activeSubscriptions": { "type": "integer" }, "byTier": { "type": "array", "items": { "type": "object", "properties": { "tier": { "type": "string" }, "count": { "type": "integer" }, "revenue": { "type": "integer" } }, "required": [ "tier", "count", "revenue" ] } } }, "required": [ "mrr", "arr", "totalSubscriptions", "activeSubscriptions", "byTier" ] }, "PlatformMetrics": { "type": "object", "properties": { "platform": { "type": "string" }, "accounts": { "type": "integer" }, "color": { "type": "string" } }, "required": [ "platform", "accounts", "color" ] }, "ScheduledPost": { "type": "object", "properties": { "id": { "type": "string" }, "title": { "type": "string" }, "scheduledFor": { "type": "string" }, "platform": { "type": "string" }, "orgName": { "type": "string" } }, "required": [ "id", "title", "scheduledFor", "platform", "orgName" ] }, "SystemAnalyticsResponse": { "type": "object", "properties": { "metrics": { "$ref": "#/components/schemas/AnalyticsMetrics" }, "signupData": { "type": "array", "items": { "type": "object", "properties": { "date": { "type": "string" }, "value": { "type": "integer" }, "users": { "type": "integer" }, "posts": { "type": "integer" }, "scheduled": { "type": "integer" } }, "required": [ "date", "value", "users", "posts", "scheduled" ] } }, "postsData": { "type": "array", "items": { "type": "object", "properties": { "date": { "type": "string" }, "value": { "type": "integer" }, "users": { "type": "integer" }, "posts": { "type": "integer" }, "scheduled": { "type": "integer" } }, "required": [ "date", "value", "users", "posts", "scheduled" ] } }, "activeOrgs": { "type": "array", "items": { "$ref": "#/components/schemas/ActiveWorkspace" } }, "revenue": { "$ref": "#/components/schemas/RevenueMetrics" }, "platformBreakdown": { "type": "array", "items": { "$ref": "#/components/schemas/PlatformMetrics" } }, "topContent": { "type": "object", "properties": { "scheduledPosts": { "type": "array", "items": { "$ref": "#/components/schemas/ScheduledPost" } } }, "required": [ "scheduledPosts" ] } }, "required": [ "metrics", "signupData", "postsData", "activeOrgs", "revenue", "platformBreakdown", "topContent" ] }, "SystemWorkspace": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "plan": { "type": "string" }, "status": { "type": "string" }, "ownerEmail": { "type": "string" }, "ownerName": { "type": "string", "nullable": true }, "memberCount": { "type": "integer" }, "postCount": { "type": "integer" }, "accountCount": { "type": "integer" }, "createdAt": { "type": "string" } }, "required": [ "id", "name", "slug", "plan", "status", "ownerEmail", "ownerName", "memberCount", "postCount", "accountCount", "createdAt" ] }, "SystemWorkspaceListResponse": { "type": "object", "properties": { "workspaces": { "type": "array", "items": { "$ref": "#/components/schemas/SystemWorkspace" } }, "pagination": { "type": "object", "properties": { "page": { "type": "integer" }, "limit": { "type": "integer" }, "total": { "type": "integer" }, "totalPages": { "type": "integer" } }, "required": [ "page", "limit", "total", "totalPages" ] } }, "required": [ "workspaces", "pagination" ] }, "SystemWorkspaceDetail": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "ownerEmail": { "type": "string" }, "ownerName": { "type": "string", "nullable": true }, "ownerId": { "type": "string" }, "memberCount": { "type": "integer" }, "postCount": { "type": "integer" }, "accountCount": { "type": "integer" }, "plan": { "type": "string" }, "status": { "type": "string" }, "createdAt": { "type": "string" }, "updatedAt": { "type": "string" } }, "required": [ "id", "name", "slug", "ownerEmail", "ownerName", "memberCount", "postCount", "accountCount", "plan", "status", "createdAt", "updatedAt" ] }, "SystemWorkspaceMembers": { "type": "object", "properties": { "workspace": { "$ref": "#/components/schemas/SystemWorkspaceDetail" }, "members": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "userId": { "type": "string" }, "email": { "type": "string" }, "name": { "type": "string", "nullable": true }, "role": { "type": "string" }, "joinedAt": { "type": "string" } }, "required": [ "id", "userId", "email", "name", "role", "joinedAt" ] } }, "accounts": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "platform": { "type": "string" }, "username": { "type": "string" }, "status": { "type": "string" }, "connectedAt": { "type": "string" } }, "required": [ "id", "platform", "username", "status", "connectedAt" ] } } }, "required": [ "workspace", "members", "accounts" ] }, "SystemUser": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "name": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true }, "externalId": { "type": "string", "nullable": true }, "workspaces": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "role": { "type": "string" } }, "required": [ "id", "name", "role" ] } }, "status": { "type": "string" }, "createdAt": { "type": "string" } }, "required": [ "id", "email", "name", "avatarUrl", "externalId", "workspaces", "status", "createdAt" ] }, "SystemUserListResponse": { "type": "object", "properties": { "users": { "type": "array", "items": { "$ref": "#/components/schemas/SystemUser" } }, "pagination": { "type": "object", "properties": { "page": { "type": "integer" }, "limit": { "type": "integer" }, "total": { "type": "integer" }, "totalPages": { "type": "integer" } }, "required": [ "page", "limit", "total", "totalPages" ] } }, "required": [ "users", "pagination" ] }, "SystemUserDetail": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "name": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true }, "externalId": { "type": "string", "nullable": true }, "workspaces": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "slug": { "type": "string" }, "role": { "type": "string" }, "joinedAt": { "type": "string" } }, "required": [ "id", "name", "slug", "role", "joinedAt" ] } }, "status": { "type": "string" }, "createdAt": { "type": "string" }, "lastLoginAt": { "type": "string" }, "emailVerified": { "type": "boolean" } }, "required": [ "id", "email", "name", "avatarUrl", "externalId", "workspaces", "status", "createdAt" ] }, "SystemSubscription": { "type": "object", "properties": { "id": { "type": "string" }, "workspaceId": { "type": "string" }, "workspaceName": { "type": "string" }, "workspaceSlug": { "type": "string" }, "stripeCustomerId": { "type": "string", "nullable": true }, "stripeSubscriptionId": { "type": "string", "nullable": true }, "plan": { "type": "string" }, "status": { "type": "string" }, "currentPeriodStart": { "type": "string", "nullable": true }, "currentPeriodEnd": { "type": "string", "nullable": true }, "cancelAtPeriodEnd": { "type": "boolean" }, "trialEnd": { "type": "string", "nullable": true }, "createdAt": { "type": "string" }, "isSynthetic": { "type": "boolean" } }, "required": [ "id", "workspaceId", "workspaceName", "stripeCustomerId", "stripeSubscriptionId", "plan", "status", "currentPeriodStart", "currentPeriodEnd", "cancelAtPeriodEnd", "trialEnd", "createdAt", "isSynthetic" ] }, "SystemSubscriptionListResponse": { "type": "object", "properties": { "subscriptions": { "type": "array", "items": { "$ref": "#/components/schemas/SystemSubscription" } }, "metrics": { "type": "object", "properties": { "mrr": { "type": "integer" }, "arr": { "type": "integer" }, "totalSubscriptions": { "type": "integer" }, "activeSubscriptions": { "type": "integer" }, "byTier": { "type": "array", "items": { "type": "object", "properties": { "tier": { "type": "string" }, "count": { "type": "integer" }, "revenue": { "type": "integer" } }, "required": [ "tier", "count", "revenue" ] } } }, "required": [ "mrr", "arr", "totalSubscriptions", "activeSubscriptions", "byTier" ] } }, "required": [ "subscriptions", "metrics" ] }, "AdminPlatformConfig": { "type": "object", "properties": { "id": { "type": "string" }, "platformKey": { "type": "string" }, "name": { "type": "string" }, "shortName": { "type": "string" }, "icon": { "type": "string" }, "color": { "type": "string" }, "bgColor": { "type": "string" }, "isEnabled": { "type": "boolean" }, "isConfigured": { "type": "boolean" }, "isAvailable": { "type": "boolean" }, "authMethod": { "type": "string" }, "usesPKCE": { "type": "boolean" }, "tokenExpires": { "type": "boolean" }, "supportsRefresh": { "type": "boolean" }, "activeAccounts": { "type": "integer" }, "errorAccounts": { "type": "integer" }, "credentialsUpdatedAt": { "type": "string", "nullable": true }, "enabledAt": { "type": "string", "nullable": true }, "disabledAt": { "type": "string", "nullable": true }, "updatedAt": { "type": "string" } }, "required": [ "id", "platformKey", "name", "shortName", "icon", "color", "bgColor", "isEnabled", "isConfigured", "isAvailable", "authMethod", "usesPKCE", "tokenExpires", "supportsRefresh", "activeAccounts", "errorAccounts", "credentialsUpdatedAt", "enabledAt", "disabledAt", "updatedAt" ] }, "AdminPlatformListResponse": { "type": "object", "properties": { "platforms": { "type": "array", "items": { "$ref": "#/components/schemas/AdminPlatformConfig" } }, "summary": { "type": "object", "properties": { "total": { "type": "integer" }, "enabled": { "type": "integer" }, "configured": { "type": "integer" } }, "required": [ "total", "enabled", "configured" ] } }, "required": [ "platforms", "summary" ] } }, "parameters": {} }, "paths": { "/v1/workspaces/{id}/request-history": { "get": { "tags": [ "Analytics", "Workspaces" ], "summary": "List request history", "description": "Returns a paginated log of API requests made within the workspace. Useful for debugging integrations and auditing usage.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "GET", "POST", "PATCH", "PUT", "DELETE" ] }, "required": false, "name": "method", "in": "query" }, { "schema": { "type": "string", "maxLength": 500 }, "required": false, "name": "path", "in": "query" }, { "schema": { "type": "string", "pattern": "^\\d{3}$" }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "apiKeyId", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "cursor", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Paginated list of request history entries", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/RequestHistoryItem" } }, "nextCursor": { "type": "string", "nullable": true, "description": "Cursor for the next page, null if no more pages" }, "hasMore": { "type": "boolean", "description": "Whether there are more items to fetch" } }, "required": [ "data", "nextCursor", "hasMore" ] } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – insufficient workspace role" } } } }, "/v1/workspaces/{id}/api-keys/{keyId}/usage": { "get": { "tags": [ "API Keys", "Analytics" ], "summary": "Get per-key usage statistics", "description": "Returns detailed usage statistics for a specific API key including request counts, per-endpoint breakdown, and average response time.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "description": "API key ID" }, "required": true, "name": "keyId", "in": "path" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "endDate", "in": "query" } ], "responses": { "200": { "description": "Per-key usage statistics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiKeyUsageResponse" } } } }, "401": { "description": "Unauthorized" }, "404": { "description": "API key not found" } } } }, "/v1/workspaces/{id}/analytics/errors": { "get": { "tags": [ "Analytics", "Workspaces" ], "summary": "Get error rate analytics", "description": "Returns 4xx/5xx error rates and top failing endpoints for the workspace over a configurable time window.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "24h", "7d", "30d" ], "default": "24h" }, "required": false, "name": "range", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10 }, "required": false, "name": "topN", "in": "query" } ], "responses": { "200": { "description": "Error rate analytics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorRatesResponse" } } } }, "401": { "description": "Unauthorized" } } } }, "/v1/batch/async": { "post": { "tags": [ "Batch" ], "summary": "Submit async batch job", "description": "Submit a batch of operations for asynchronous processing via SQS. Returns a job ID immediately. Poll GET /v1/batch/async/{jobId} for status.", "security": [ { "BearerAuth": [] } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "operations": { "type": "array", "items": { "type": "object", "properties": { "method": { "type": "string", "enum": [ "GET", "POST", "PUT", "PATCH", "DELETE" ] }, "path": { "type": "string" }, "body": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "method", "path" ] } }, "callbackUrl": { "type": "string", "format": "uri", "description": "Webhook URL to notify when job completes" } }, "required": [ "operations" ] } } } }, "responses": { "202": { "description": "Batch job accepted for processing", "content": { "application/json": { "schema": { "type": "object", "properties": { "jobId": { "type": "string" }, "status": { "type": "string", "enum": [ "queued" ] }, "totalOperations": { "type": "integer" } }, "required": [ "jobId", "status", "totalOperations" ] } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } }, "get": { "tags": [ "Batch" ], "summary": "List async batch jobs", "description": "Lists recent async batch jobs for the authenticated workspace.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "queued", "processing", "completed", "failed" ] }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "List of batch jobs", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AsyncBatchJob" } }, "nextCursor": { "type": "string", "nullable": true, "description": "Cursor for the next page, null if no more pages" }, "hasMore": { "type": "boolean", "description": "Whether there are more items to fetch" } }, "required": [ "data", "nextCursor", "hasMore" ] } } } }, "401": { "description": "Unauthorized" } } } }, "/v1/batch/async/{jobId}": { "get": { "tags": [ "Batch" ], "summary": "Get async batch job status", "description": "Returns the current status and results (if completed) for an async batch job.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "description": "Batch job ID" }, "required": true, "name": "jobId", "in": "path" } ], "responses": { "200": { "description": "Batch job status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AsyncBatchJob" } } } }, "401": { "description": "Unauthorized" }, "404": { "description": "Job not found" } } } }, "/v1/workspaces/{id}/api-usage/timeseries": { "get": { "tags": [ "Analytics", "Workspaces" ], "summary": "Get API usage timeseries", "description": "Returns time-bucketed API request counts for charting. Supports hourly or daily granularity over configurable ranges.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "7d", "30d", "90d" ], "default": "30d" }, "required": false, "name": "range", "in": "query" }, { "schema": { "type": "string", "enum": [ "hourly", "daily" ], "default": "daily" }, "required": false, "name": "granularity", "in": "query" } ], "responses": { "200": { "description": "Timeseries data points", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "timestamp": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "requests": { "type": "integer", "example": 1523 }, "errors": { "type": "integer", "example": 12 } }, "required": [ "timestamp", "requests", "errors" ] } } }, "required": [ "data" ] } } } }, "400": { "description": "Invalid range or granularity" }, "401": { "description": "Unauthorized" } } } }, "/v1/workspaces/{id}/api-usage/endpoints": { "get": { "tags": [ "Analytics", "Workspaces" ], "summary": "Get per-endpoint usage breakdown", "description": "Returns per-endpoint request counts, average response time, and error rates for the workspace.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "7d", "30d", "90d" ], "default": "30d" }, "required": false, "name": "range", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Per-endpoint usage breakdown", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": { "method": { "type": "string", "example": "POST" }, "path": { "type": "string", "example": "/v1/posts" }, "requests": { "type": "integer", "example": 4521 }, "errors": { "type": "integer", "example": 23 }, "errorRate": { "type": "number", "example": 0.005 }, "avgResponseTimeMs": { "type": "number", "nullable": true, "example": 187.4 } }, "required": [ "method", "path", "requests", "errors", "errorRate", "avgResponseTimeMs" ] } } }, "required": [ "data" ] } } } }, "400": { "description": "Invalid range" }, "401": { "description": "Unauthorized" } } } }, "/v1/workspaces/{id}/api-keys/{keyId}": { "patch": { "tags": [ "API Keys", "Workspaces" ], "summary": "Update API key settings", "description": "Update an API key's name, scopes, or IP allowlist. IP allowlist accepts individual IPs or CIDR notation.", "security": [ { "BearerAuth": [] } ], "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "description": "API key ID" }, "required": true, "name": "keyId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "scopes": { "type": "array", "items": { "type": "string" } }, "allowedIps": { "type": "array", "items": { "type": "string" }, "description": "IP addresses or CIDR ranges allowed to use this key. Empty array removes restrictions.", "example": [ "203.0.113.0/24", "198.51.100.42" ] } } } } } }, "responses": { "200": { "description": "Updated API key", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "prefix": { "type": "string" }, "scopes": { "type": "array", "items": { "type": "string" } }, "allowedIps": { "type": "array", "items": { "type": "string" } }, "expiresAt": { "type": "string", "nullable": true, "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "name", "prefix", "scopes", "allowedIps", "expiresAt", "updatedAt" ] } }, "required": [ "data" ] } } } }, "400": { "description": "Invalid IP address or CIDR notation" }, "401": { "description": "Unauthorized" }, "404": { "description": "API key not found" } } } }, "/v1/status/platforms": { "get": { "tags": [ "Status" ], "summary": "Get all platform statuses", "description": "Returns operational status for each supported platform. No authentication required.\n\n**Status levels:**\n- `operational`: Error rate < 10% and recent successful publishes\n- `degraded`: Error rate 10-50% or no publishes in last 2 hours\n- `down`: Error rate > 50% or no successful publish in 6+ hours", "security": [], "responses": { "200": { "description": "Platform status list", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlatformStatusResponse" } } } } } } }, "/v1/posts": { "post": { "tags": [ "Posts" ], "summary": "Create a new post", "description": "Create a new social media post. The post can be:\n- **Scheduled**: Set `scheduledFor` to a future datetime\n- **Queued**: Set `queue: true` to use the next available queue slot\n- **Draft**: Omit both to create as a draft\n\nSupports idempotency via the `Idempotency-Key` header.\n\n## Example\n\n```bash\ncurl -X POST https://api.voxburst.io/v1/posts \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"content\":\"Hello World!\",\"accountIds\":[\"550e8400-e29b-41d4-a716-446655440000\"]}'\n```", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePostRequest" } } } }, "responses": { "201": { "description": "Post created successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Post" } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "enum": [ "VALIDATION_ERROR" ] }, "message": { "type": "string" }, "details": { "type": "object", "additionalProperties": { "nullable": true } } }, "required": [ "code", "message" ] } }, "required": [ "error" ] } } } }, "401": { "description": "Authentication required" }, "403": { "description": "Insufficient permissions" }, "429": { "description": "Rate limit exceeded" } } }, "get": { "tags": [ "Posts" ], "summary": "List posts", "description": "List posts with optional filtering and pagination.", "parameters": [ { "schema": { "type": "string", "enum": [ "draft", "scheduled", "publishing", "published", "failed", "all" ], "description": "Filter by post status", "example": "scheduled" }, "required": false, "name": "status", "in": "query" }, { "schema": { "$ref": "#/components/schemas/Platform" }, "required": false, "name": "platform", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "Filter posts scheduled after this time" }, "required": false, "name": "from", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "Filter posts scheduled before this time" }, "required": false, "name": "to", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20, "description": "Maximum items to return", "example": 20 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "description": "Pagination cursor from previous response" }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "List of posts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PostListResponse" } } } }, "401": { "description": "Authentication required" } } } }, "/v1/posts/{id}": { "get": { "tags": [ "Posts" ], "summary": "Get a post (including status)", "description": "Retrieve a single post by ID, including its current publishing status.\n\nThis is the primary endpoint to check post status after publishing. The `status` field indicates:\n- `DRAFT` - Post created but not scheduled or queued\n- `SCHEDULED` - Scheduled for future publishing\n- `PUBLISHING` - Currently being published to platforms\n- `PUBLISHED` - Successfully published to all platforms\n- `PARTIAL` - Published to some platforms, failed on others\n- `FAILED` - All platforms failed to publish\n\n## Polling for Status\n\nIf not using sync mode or webhooks, poll this endpoint every 2-5 seconds:\n\n```bash\ncurl https://api.voxburst.io/v1/posts/123 \\\n -H \"Authorization: Bearer $TOKEN\"\n```\n\n## Response includes:\n- `status` - Overall post status\n- `platformStatus` - Array of per-platform results with error details\n- `publishedAt` - When publishing completed (if successful)", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Post ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Post details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Post" } } } }, "404": { "description": "Post not found" } } }, "patch": { "tags": [ "Posts" ], "summary": "Update a post", "description": "Update a draft or scheduled post. Published posts cannot be updated.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdatePostRequest" } } } }, "responses": { "200": { "description": "Post updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Post" } } } }, "400": { "description": "Cannot update post in current status" }, "404": { "description": "Post not found" } } }, "delete": { "tags": [ "Posts" ], "summary": "Delete a post", "description": "Delete a post. Published posts can be deleted but the social media content remains.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Post deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "404": { "description": "Post not found" } } } }, "/v1/posts/{id}/publish": { "post": { "tags": [ "Posts" ], "summary": "Publish a post immediately", "description": "Publish a draft or scheduled post immediately to all target platforms.\n\nSupports idempotency via the `Idempotency-Key` header.\n\n## Important: Post ID ≠ Success\n\nThe `postId` returned in the response does **NOT** indicate successful publishing.\nIt only means the post was queued in the VoxBurst system.\n\nPlatform publishing happens asynchronously. Always check the `status` field\nor use `?sync=true` to wait for final platform status.\n\n## Platform Publish Lifecycle\n\n1. `DRAFT` → Post created\n2. `SCHEDULED` → Scheduled for future\n3. `PUBLISHING` → Queued for immediate publishing\n4. `PUBLISHED` ✅ → Live on all platforms\n5. `PARTIAL` ⚠️ → Published on some platforms, failed on others\n6. `FAILED` ❌ → All platforms failed\n\n## Sync Mode\n\nAdd `?sync=true` to wait for publishing to complete:\n- Default timeout: 30 seconds\n- Custom timeout: `?sync=true&timeout=60` (max 120s)\n- Returns final platform results when complete\n- Returns `\"timeout\": true` if still processing\n\n## Webhook Callbacks\n\nInclude `X-Callback-Url` header to receive a webhook when publishing completes:\n- VoxBurst will POST the result to your URL\n- Includes per-platform success/failure details\n- Retry: 3 attempts with exponential backoff\n\n## Code Examples\n\n### Basic Publish\n```bash\ncurl -X POST https://api.voxburst.io/v1/posts/123/publish \\\n -H \"Authorization: Bearer $TOKEN\"\n```\n\n### Sync Mode (wait for completion)\n```bash\ncurl -X POST \"https://api.voxburst.io/v1/posts/123/publish?sync=true&timeout=60\" \\\n -H \"Authorization: Bearer $TOKEN\"\n```\n\n### With Webhook Callback\n```bash\ncurl -X POST https://api.voxburst.io/v1/posts/123/publish \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"X-Callback-Url: https://yourapp.com/webhooks/voxburst\"\n```\n\n### Idempotent Publish\n```bash\ncurl -X POST https://api.voxburst.io/v1/posts/123/publish \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Idempotency-Key: publish-123-attempt-1\"\n```\n\n## Instagram Edge Cases\n\n- Media container creation can take 3–15 seconds\n- Container must reach `FINISHED` status before publish succeeds\n- JPEG is the only supported image format\n- Rate limit: 100 API-published posts per 24 hours\n- Silent failures: always verify via status endpoint\n\n## Facebook Edge Cases\n\n- Pages under Business Accounts require `business_management` permission\n- The `pageId` must be set via `POST /v1/accounts/{id}/select-page` after OAuth\n- If only one page is available, VoxBurst auto-selects it during OAuth", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Post ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": [ "true", "false" ], "description": "Wait for publishing to complete before returning. Polls every 2 seconds until a terminal status is reached.", "example": "true" }, "required": false, "name": "sync", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 120, "description": "Max seconds to wait when using sync mode (default 30, max 120).", "example": 30 }, "required": false, "name": "timeout", "in": "query" }, { "schema": { "type": "string", "format": "uri", "description": "Webhook URL to call when publishing completes. VoxBurst will POST platform results to this URL with up to 3 retries (exponential backoff).", "example": "https://yourapp.com/webhooks/voxburst" }, "required": false, "name": "X-Callback-Url", "in": "header" }, { "schema": { "type": "string", "description": "Unique key to prevent duplicate publishes on retry", "example": "publish-post-abc123-v1" }, "required": false, "name": "Idempotency-Key", "in": "header" } ], "responses": { "200": { "description": "Post queued for publishing (or final result when using sync mode)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublishResponse" } } } }, "400": { "description": "Cannot publish post in current status (e.g. already published, media not ready)" }, "404": { "description": "Post not found" } } } }, "/v1/posts/{id}/retry": { "post": { "tags": [ "Posts" ], "summary": "Retry a failed post", "description": "Retry publishing a failed or partially published post.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Retry initiated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Post" } } } }, "400": { "description": "Post is not in a retryable state" }, "404": { "description": "Post not found" } } } }, "/v1/accounts": { "get": { "tags": [ "Accounts" ], "summary": "List connected accounts", "description": "List all connected social media accounts for the workspace.", "parameters": [ { "schema": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Filter by platform (case-insensitive; uppercased server-side)" } ] }, "required": false, "name": "platform", "in": "query" }, { "schema": { "type": "string", "enum": [ "ACTIVE", "INACTIVE", "ERROR", "all" ], "description": "Filter by status. Omit to use the default filter, which excludes DISCONNECTED accounts." }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "boolean", "nullable": true, "default": false, "description": "Include DISCONNECTED (archived) accounts. Ignored when an explicit `status` is supplied." }, "required": false, "name": "includeArchived", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20, "description": "Maximum items to return" }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "description": "Pagination cursor" }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "List of accounts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountListResponse" } } } } } } }, "/v1/accounts/{id}": { "get": { "tags": [ "Accounts" ], "summary": "Get account details", "description": "Retrieve details for a specific connected account.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Account details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Account" } } } }, "404": { "description": "Account not found" } } }, "delete": { "tags": [ "Accounts" ], "summary": "Disconnect account", "description": "Disconnect a social media account from the workspace.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Account disconnected", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "404": { "description": "Account not found" } } } }, "/v1/accounts/connect/{platform}": { "post": { "tags": [ "Accounts" ], "summary": "Connect account (initiate OAuth)", "description": "Initiate OAuth flow to connect a social media account. Pass `forcePrompt: true` to show the account picker when adding another account to the same platform (multi-account support).\n\n## Facebook OAuth Flow\n\nFacebook requires a **Page-level** connection to publish posts:\n\n1. Initiate OAuth with `platform: FACEBOOK` — this requests `pages_manage_posts`, `pages_read_engagement`, and `business_management` scopes.\n2. User authorizes and is redirected back to your `callbackUrl`.\n3. VoxBurst exchanges the code for a user token and fetches the list of Pages the user manages.\n4. **If the user has exactly one Page**, VoxBurst auto-selects it — no further action needed.\n5. **If the user has multiple Pages**, you must call `POST /v1/accounts/{id}/select-page` to choose which Page to post as.\n\n> **Note:** Pages under Business Manager accounts may require the `business_management` scope, which VoxBurst requests automatically.\n\n## Instagram OAuth Flow\n\nInstagram uses **Direct Login** (Instagram Graph API with Instagram-linked account):\n\n1. Initiate OAuth with `platform: INSTAGRAM`.\n2. The user authorizes access to their Instagram Professional Account (Creator or Business).\n3. No Facebook Page selection is required — VoxBurst connects directly to the Instagram account.\n\n> **Note:** Instagram personal accounts are not supported. The account must be a Professional Account (Business or Creator).\n\n## LinkedIn OAuth Flow (Unified)\n\nLinkedIn uses a **unified connection** that supports both personal profiles and company pages:\n\n1. Initiate OAuth with `platform: LINKEDIN` — this requests all required scopes:\n - `openid`, `profile`, `email` — user identity\n - `w_member_social` — post to personal profile\n - `r_organization_social`, `w_organization_social` — read/write organization posts\n - `rw_organization_admin` — manage organization admin (discover pages)\n2. User authorizes and is redirected back to your `callbackUrl`.\n3. VoxBurst fetches the user's profile and their admin organizations (company pages).\n4. **If the user has exactly one company page**, VoxBurst auto-selects it — no further action needed.\n5. **If the user has multiple destinations** (personal + multiple pages), call `GET /v1/accounts/{id}/pages` to list them, then `POST /v1/accounts/{id}/select-page` to choose.\n\n> **Important:** Some scopes (`r_organization_social`, `w_organization_social`, `rw_organization_admin`) require LinkedIn Marketing Developer Program approval. Without approval, only personal profile posting will work.\n\n### Author URN Format\n\nThe post destination is determined by the author URN in publish requests:\n- Personal profile: `urn:li:person:{personId}`\n- Company page: `urn:li:organization:{organizationId}`", "parameters": [ { "schema": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ], "description": "Platform to connect" }, "required": true, "name": "platform", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "callbackUrl": { "type": "string", "format": "uri", "description": "OAuth redirect URL after user authorization", "example": "https://app.voxburst.io/callback" }, "forcePrompt": { "type": "boolean", "description": "Force account picker — use true when adding another account to the same platform (multi-account support)", "example": true } }, "required": [ "callbackUrl" ] } } } }, "responses": { "200": { "description": "OAuth authorization URL", "content": { "application/json": { "schema": { "type": "object", "properties": { "authUrl": { "type": "string", "format": "uri", "description": "OAuth authorization URL to redirect the user to" }, "state": { "type": "string", "description": "OAuth state parameter (verify on callback to prevent CSRF)" } }, "required": [ "authUrl", "state" ] } } } }, "402": { "description": "Account limit exceeded for plan" } } } }, "/v1/accounts/{id}/select-page": { "post": { "tags": [ "Accounts" ], "summary": "Select Page / Organization", "description": "After connecting an account that manages multiple Pages or Organizations, use this endpoint to choose which destination to post as.\n\n**Facebook:**\n- Use this when the user manages more than one Facebook Page.\n- If the user has exactly one Page, VoxBurst auto-selects it during OAuth — you can skip this step.\n- Pass the Facebook Page ID as `pageId`.\n\n**LinkedIn:**\n- Use this when the user has multiple destinations (personal + company pages).\n- `GET /v1/accounts/{id}/pages` lists all available destinations. (`GET /v1/accounts/{id}` does **not** return account metadata.)\n- Pass the destination's `externalId` as `pageId`.\n- Pass an empty `pageId` (`''`) to post as the personal profile.\n\n**Instagram (Facebook Login accounts only):**\n- Pass the Facebook Page ID as `pageId`.\n- Accounts connected via Instagram Direct Login return `400 PAGE_SELECTION_NOT_SUPPORTED` — check `oauthVersion` on the account first.\n\n**Page ownership:** the selected Page must belong to the account identified by `id`. Selecting a Page that belongs to a different connected account returns `400 ACCOUNT_PAGE_MISMATCH` and writes nothing.\n\n**How to discover available Pages:** Call `GET /v1/accounts/{id}/pages` to list all available destinations with their IDs and names. That response can be a superset of the Pages selectable onto any one account.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Account ID (Facebook, Instagram or LinkedIn account)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "pageId": { "type": "string", "description": "Page/Organization ID to post as. Pass empty string for personal profile (LinkedIn only).", "example": "123456789012345" }, "pageName": { "type": "string", "description": "Display name of the selected page (for reference)", "example": "Acme Corporation" } }, "required": [ "pageId" ] } } } }, "responses": { "200": { "description": "Page selected — account is now ready to publish", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "400": { "description": "Invalid pageId or account type does not support page selection" }, "404": { "description": "Account not found" } } } }, "/v1/accounts/{id}/pages": { "get": { "tags": [ "Accounts" ], "summary": "List selectable pages/organizations", "description": "List all available posting destinations for an account.\n\n**Facebook:** Returns the Facebook Pages the user manages.\n\n**Instagram (Facebook Login accounts only):** Returns the Instagram Business accounts reachable via the connected Facebook token, each with its `pageId` and `pageName`. Accounts connected via Instagram Direct Login return an empty list. This response can be a superset of the Pages selectable onto any one account — see `select-page`.\n\n**LinkedIn:** Returns the user's personal profile and company pages they admin.\nEach destination includes:\n- `id`: The external ID to pass to `select-page`\n- `name`: Display name\n- `urn`: LinkedIn URN (e.g., `urn:li:organization:123456`)\n- `type`: `person` or `organization`\n- `logoUrl`: Optional logo/image URL", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Account ID (Facebook, Instagram or LinkedIn account)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "List of available pages/destinations", "content": { "application/json": { "schema": { "type": "object", "properties": { "pages": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "Page/Organization external ID" }, "name": { "type": "string", "description": "Display name" }, "urn": { "type": "string", "description": "LinkedIn URN (LinkedIn only)" }, "type": { "type": "string", "enum": [ "person", "organization" ], "description": "Destination type (LinkedIn only)" }, "logoUrl": { "type": "string", "description": "Logo/image URL" } }, "required": [ "id", "name" ] } } }, "required": [ "pages" ] } } } }, "404": { "description": "Account not found" } } } }, "/v1/accounts/{id}/refresh": { "post": { "tags": [ "Accounts" ], "summary": "Refresh account tokens", "description": "Manually trigger a token refresh for an account with expiring credentials. Returns an acknowledgement only — re-fetch `GET /v1/accounts/{id}` if you need the updated account.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Tokens refreshed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "400": { "description": "Token refresh not supported for this platform" }, "404": { "description": "Account not found" } } } }, "/v1/webhooks": { "get": { "tags": [ "Webhooks" ], "summary": "List webhook endpoints", "description": "List all configured webhook endpoints for the workspace.", "responses": { "200": { "description": "List of webhook endpoints", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookEndpoint" } } }, "required": [ "data" ] } } } } } }, "post": { "tags": [ "Webhooks" ], "summary": "Create webhook endpoint", "description": "Create a new webhook endpoint. The signing secret is returned once in the response.\nStore it securely - it cannot be retrieved again.\n\n**Signature Verification:**\nAll webhook deliveries include a signature header:\n```\nX-VoxBurst-Signature: t=,v2=\n```\n\nVerify using HMAC-SHA256 of `{timestamp}.{payload}` with your signing secret.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWebhookEndpointRequest" } } } }, "responses": { "201": { "description": "Endpoint created (includes signing secret)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpointWithSecret" } } } }, "400": { "description": "Invalid webhook URL or events" } } } }, "/v1/webhooks/{id}": { "get": { "tags": [ "Webhooks" ], "summary": "Get webhook endpoint", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Webhook endpoint details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpoint" } } } }, "404": { "description": "Endpoint not found" } } }, "patch": { "tags": [ "Webhooks" ], "summary": "Update webhook endpoint", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateWebhookEndpointRequest" } } } }, "responses": { "200": { "description": "Endpoint updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEndpoint" } } } }, "404": { "description": "Endpoint not found" } } }, "delete": { "tags": [ "Webhooks" ], "summary": "Delete webhook endpoint", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Endpoint deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "404": { "description": "Endpoint not found" } } } }, "/v1/webhooks/{id}/rotate-secret": { "post": { "tags": [ "Webhooks" ], "summary": "Rotate signing secret", "description": "Generate a new signing secret. The old secret is immediately invalidated.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "New secret generated", "content": { "application/json": { "schema": { "type": "object", "properties": { "secret": { "type": "string", "description": "New signing secret" } }, "required": [ "secret" ] } } } }, "404": { "description": "Endpoint not found" } } } }, "/v1/webhooks/test": { "post": { "tags": [ "Webhooks" ], "summary": "Send test webhook", "description": "Send a test payload to a registered webhook and return the delivery result.", "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "webhookId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" } }, "required": [ "webhookId" ] } } } }, "responses": { "200": { "description": "Test delivery result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookDelivery" } } } } } } }, "/v1/webhooks/{id}/deliveries": { "get": { "tags": [ "Webhooks" ], "summary": "List webhook deliveries", "description": "List recent delivery attempts for a webhook endpoint.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20, "description": "Maximum items to return" }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "List of deliveries", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/WebhookDelivery" } }, "nextCursor": { "type": "string", "nullable": true }, "hasMore": { "type": "boolean" } }, "required": [ "data", "nextCursor", "hasMore" ] } } } } } } }, "/v1/workspaces": { "get": { "tags": [ "Workspaces" ], "summary": "List workspaces", "description": "List all workspaces the authenticated user has access to.", "responses": { "200": { "description": "List of workspaces", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Workspace" } } }, "required": [ "data" ] } } } } } }, "post": { "tags": [ "Workspaces" ], "summary": "Create workspace", "description": "Create a new workspace. The authenticated user becomes the owner.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateWorkspaceRequest" } } } }, "responses": { "201": { "description": "Workspace created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Workspace" } } } }, "400": { "description": "Slug already taken" } } } }, "/v1/workspaces/{id}": { "get": { "tags": [ "Workspaces" ], "summary": "Get workspace", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Workspace details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Workspace" } } } }, "404": { "description": "Workspace not found" } } }, "patch": { "tags": [ "Workspaces" ], "summary": "Update workspace", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateWorkspaceRequest" } } } }, "responses": { "200": { "description": "Workspace updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Workspace" } } } }, "403": { "description": "Admin role required" }, "404": { "description": "Workspace not found" } } }, "delete": { "tags": [ "Workspaces" ], "summary": "Delete workspace", "description": "Permanently delete a workspace and all associated data. Requires owner role.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Workspace deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "403": { "description": "Owner role required" }, "404": { "description": "Workspace not found" } } } }, "/v1/workspaces/{id}/members": { "get": { "tags": [ "Workspace Members", "Workspaces" ], "summary": "List workspace members", "description": "List all members of a workspace.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Workspace ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "List of members", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemberListResponse" } } } }, "401": { "description": "Authentication required" }, "403": { "description": "Permission denied" }, "404": { "description": "Workspace not found" } } }, "post": { "tags": [ "Workspace Members", "Workspaces" ], "summary": "Invite a new member", "description": "Invite a new member to the workspace by email.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Workspace ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/InviteMemberRequest" }, { "properties": { "email": { "type": "string", "format": "email", "description": "Email address of the member to invite", "example": "colleague@example.com" }, "role": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ], "default": "MEMBER", "description": "Member role in the workspace" } } } ] } } } }, "responses": { "201": { "description": "Member invited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemberResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Authentication required" }, "403": { "description": "Only admins and owners can invite members" }, "404": { "description": "Workspace not found" }, "409": { "description": "User is already a member" } } } }, "/v1/workspaces/{id}/invitations": { "post": { "tags": [ "Workspaces" ], "summary": "Invite member", "description": "Send an invitation to join the workspace.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InviteMemberRequest" } } } }, "responses": { "201": { "description": "Invitation sent", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "email": { "type": "string", "format": "email" }, "role": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ], "description": "Role in the workspace" }, "expiresAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "email", "role", "expiresAt" ] } } } }, "400": { "description": "User already a member" }, "403": { "description": "Admin role required" } } }, "get": { "tags": [ "Invitations", "Workspaces" ], "summary": "List workspace invitations (Admin)", "description": "Lists all pending invitations for a workspace. Requires ADMIN or OWNER role.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Workspace ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "List of workspace invitations", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListOrgInvitationsResponse" } } } }, "403": { "description": "Only admins and owners can view invitations" } } } }, "/v1/workspaces/{id}/members/{memberId}": { "patch": { "tags": [ "Workspaces" ], "summary": "Update member role", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "format": "uuid", "description": "Member ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "memberId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateMemberRoleRequest" } } } }, "responses": { "200": { "description": "Role updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WorkspaceMember" } } } }, "403": { "description": "Admin role required" }, "404": { "description": "Member not found" } } }, "delete": { "tags": [ "Workspaces" ], "summary": "Remove member", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "memberId", "in": "path" } ], "responses": { "200": { "description": "Member removed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "403": { "description": "Cannot remove workspace owner" }, "404": { "description": "Member not found" } } } }, "/v1/media/upload": { "post": { "tags": [ "Media" ], "summary": "Get upload URL", "description": "Request a pre-signed URL for uploading media. The workflow is:\n1. Call this endpoint with file metadata\n2. Upload the file directly to the returned URL\n3. Use the returned media ID when creating posts\n\nSupported formats:\n- Images: JPEG, PNG, GIF, WebP (max 20MB)\n- Videos: MP4, MOV (max 50MB)\n- GIFs: GIF (max 15MB)", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RequestUploadUrlRequest" } } } }, "responses": { "200": { "description": "Upload URL generated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UploadUrlResponse" } } } }, "400": { "description": "Invalid file type or size" } } } }, "/v1/media": { "get": { "tags": [ "Media" ], "summary": "List media", "description": "List uploaded media files.", "parameters": [ { "schema": { "type": "string", "enum": [ "image", "video", "gif" ], "description": "Type of media file" }, "required": false, "name": "type", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "List of media", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Media" } }, "next_cursor": { "type": "string", "nullable": true }, "has_more": { "type": "boolean" } }, "required": [ "data", "next_cursor", "has_more" ] } } } } } } }, "/v1/media/{id}": { "get": { "tags": [ "Media" ], "summary": "Get media details", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Media details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Media" } } } }, "404": { "description": "Media not found" } } }, "delete": { "tags": [ "Media" ], "summary": "Delete media", "description": "Delete a media file. Cannot delete if currently attached to a scheduled post.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Media deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "400": { "description": "Media is in use" }, "404": { "description": "Media not found" } } } }, "/v1/ai/enhance": { "post": { "tags": [ "AI" ], "summary": "Enhance content", "description": "Generate social media content using AI. Returns multiple variations to choose from.\n\n**Usage:** Counts against your monthly AI generation limit. Check usage with GET /v1/ai/usage.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GenerateContentRequest" } } } }, "responses": { "200": { "description": "Generated content variations", "content": { "application/json": { "schema": { "type": "object", "properties": { "variations": { "type": "array", "items": { "$ref": "#/components/schemas/GeneratedContent" } }, "usage": { "$ref": "#/components/schemas/AIUsage" } }, "required": [ "variations", "usage" ] } } } }, "400": { "description": "Invalid request" }, "402": { "description": "AI generation limit exceeded" } } } }, "/v1/ai/enhance-content": { "post": { "tags": [ "AI" ], "summary": "Enhance content with AI add-on", "description": "Enhance existing content with AI suggestions.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImproveContentRequest" } } } }, "responses": { "200": { "description": "Improved content", "content": { "application/json": { "schema": { "type": "object", "properties": { "improved": { "type": "string" }, "changes": { "type": "array", "items": { "type": "string" }, "description": "Summary of changes made" }, "usage": { "$ref": "#/components/schemas/AIUsage" } }, "required": [ "improved", "changes", "usage" ] } } } }, "402": { "description": "AI generation limit exceeded" } } } }, "/v1/ai/usage": { "get": { "tags": [ "AI" ], "summary": "Get AI usage", "description": "Check current AI generation usage and limits.", "responses": { "200": { "description": "AI usage status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AIUsage" } } } } } } }, "/v1/batch/posts": { "post": { "tags": [ "Posts" ], "summary": "Batch post operations", "description": "Perform multiple post operations in a single request. Supports create, update, and delete.\n\n**Limits:**\n- Maximum 100 operations per request\n- Request body limited to 5MB\n- Each operation is processed independently\n\n**Behavior:**\n- Partial failures allowed: some operations may succeed while others fail\n- Results array is in the same order as the request\n- All operations use the same authentication context\n\n**Example:**\n```json\n{\n \"operations\": [\n { \"operation\": \"create\", \"data\": { \"content\": \"Post 1\", \"platforms\": [\"twitter\"] } },\n { \"operation\": \"update\", \"id\": \"...\", \"data\": { \"content\": \"Updated\" } },\n { \"operation\": \"delete\", \"id\": \"...\" }\n ]\n}\n```", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchPostsRequest" } } } }, "responses": { "200": { "description": "Batch results", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BatchResponse" } } } }, "400": { "description": "Invalid request format" }, "413": { "description": "Request body too large (max 5MB)" } } } }, "/health": { "get": { "tags": [ "Health" ], "summary": "Basic health check", "description": "Returns API status. No authentication required.", "security": [], "responses": { "200": { "description": "API is healthy", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "ok" ] }, "timestamp": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "version": { "type": "string" } }, "required": [ "status", "timestamp", "version" ] } } } } } } }, "/health/all": { "get": { "tags": [ "Health" ], "summary": "Detailed health check", "description": "Returns detailed health status of all services.", "security": [], "responses": { "200": { "description": "Detailed health status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } } }, "503": { "description": "Service unhealthy", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HealthResponse" } } } } } } }, "/health/db": { "get": { "tags": [ "Health" ], "summary": "Database health check", "security": [], "responses": { "200": { "description": "Database is healthy", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ServiceHealth" } } } }, "503": { "description": "Database unhealthy" } } } }, "/health/jwks": { "get": { "tags": [ "Health" ], "summary": "JWKS cache status", "description": "Check status of the Cognito JWKS cache.", "security": [], "responses": { "200": { "description": "JWKS status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JwksHealth" } } } } } } }, "/health/jwks/refresh": { "post": { "tags": [ "Health" ], "summary": "Force JWKS refresh", "description": "Force a refresh of the JWKS cache. Use if authentication is failing.", "security": [], "responses": { "200": { "description": "Cache refreshed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JwksHealth" } } } }, "503": { "description": "Failed to fetch JWKS" } } } }, "/ready": { "get": { "tags": [ "Health" ], "summary": "Readiness check", "description": "Returns ready status. Used by load balancers.", "security": [], "responses": { "200": { "description": "Service is ready", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "ready" ] }, "timestamp": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "status", "timestamp" ] } } } }, "503": { "description": "Service not ready" } } } }, "/v1/posts/{id}/review-link": { "post": { "tags": [ "Reviews" ], "summary": "Generate review link", "description": "Generate a shareable review link for a post. Clients can review and approve/reject without logging in. Requires Pro plan or higher.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Review link generated", "content": { "application/json": { "schema": { "type": "object", "properties": { "reviewUrl": { "type": "string", "format": "uri", "description": "Shareable review URL" }, "token": { "type": "string", "description": "Review token" }, "expiresAt": { "type": "string", "format": "date-time", "description": "When the link expires", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "reviewUrl", "token", "expiresAt" ] } } } }, "402": { "description": "Pro plan or higher required" }, "404": { "description": "Post not found" } } } }, "/v1/review/{token}": { "get": { "tags": [ "Reviews" ], "summary": "View post for review", "description": "Public endpoint — no authentication required. Returns post content, media, and workspace branding for client review.", "parameters": [ { "schema": { "type": "string", "description": "Review token from the review link" }, "required": true, "name": "token", "in": "path" } ], "responses": { "200": { "description": "Post review data", "content": { "application/json": { "schema": { "type": "object", "properties": { "post": { "type": "object", "properties": { "content": { "type": "string" }, "platforms": { "type": "array", "items": { "type": "object", "properties": { "platform": { "type": "string" }, "username": { "type": "string", "nullable": true } }, "required": [ "platform", "username" ] } }, "media": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "publicUrl": { "type": "string", "format": "uri" }, "contentType": { "type": "string" } }, "required": [ "id", "publicUrl", "contentType" ] } } }, "required": [ "content", "platforms", "media" ] }, "workspace": { "type": "object", "properties": { "name": { "type": "string" }, "logo": { "type": "string", "nullable": true } }, "required": [ "name", "logo" ] }, "status": { "type": "string", "enum": [ "PENDING", "APPROVED", "REJECTED", "EXPIRED" ], "description": "Current review status" }, "expiresAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "post", "workspace", "status", "expiresAt" ] } } } }, "404": { "description": "Review link not found or expired" } } } }, "/v1/review/{token}/submit": { "post": { "tags": [ "Reviews" ], "summary": "Submit review decision", "description": "Public endpoint — no authentication required. Submit approval or rejection with optional comment.", "parameters": [ { "schema": { "type": "string", "description": "Review token" }, "required": true, "name": "token", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "decision": { "type": "string", "enum": [ "approved", "rejected" ], "description": "Review decision" }, "comment": { "type": "string", "maxLength": 2000, "description": "Reviewer comment or feedback" } }, "required": [ "decision" ] } } } }, "responses": { "200": { "description": "Review submitted", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] }, "decision": { "type": "string", "enum": [ "approved", "rejected" ], "description": "Review decision" } }, "required": [ "success", "decision" ] } } } }, "400": { "description": "Review already submitted or link expired" }, "404": { "description": "Review link not found" } } } }, "/v1/workspaces/{id}/approval-workflows": { "get": { "tags": [ "Approval Workflows" ], "summary": "List approval workflows", "description": "List all approval workflows for a workspace. Requires Pro plan or higher.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "List of workflows", "content": { "application/json": { "schema": { "type": "object", "properties": { "workflows": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "name": { "type": "string" }, "steps": { "type": "array", "items": { "$ref": "#/components/schemas/WorkflowStep" } }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "name", "steps", "createdAt", "updatedAt" ] } } }, "required": [ "workflows" ] } } } }, "402": { "description": "Pro plan or higher required" } } }, "post": { "tags": [ "Approval Workflows" ], "summary": "Create approval workflow", "description": "Create a new multi-step approval workflow. Requires Pro plan or higher.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Workflow name" }, "steps": { "type": "array", "items": { "$ref": "#/components/schemas/WorkflowStep" }, "minItems": 1, "maxItems": 10, "description": "Ordered approval steps" } }, "required": [ "name", "steps" ] } } } }, "responses": { "201": { "description": "Workflow created", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "name": { "type": "string" }, "steps": { "type": "array", "items": { "$ref": "#/components/schemas/WorkflowStep" } }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "name", "steps", "createdAt" ] } } } }, "402": { "description": "Pro plan or higher required" } } } }, "/v1/workspaces/{id}/approval-workflows/{wfId}": { "put": { "tags": [ "Approval Workflows" ], "summary": "Update approval workflow", "description": "Update an existing approval workflow.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "format": "uuid", "description": "Workflow ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "wfId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 200 }, "steps": { "type": "array", "items": { "$ref": "#/components/schemas/WorkflowStep" }, "minItems": 1, "maxItems": 10 } } } } } }, "responses": { "200": { "description": "Workflow updated" }, "404": { "description": "Workflow not found" } } } }, "/v1/posts/{id}/approve": { "post": { "tags": [ "Approval Workflows" ], "summary": "Approve current step", "description": "Approve the current approval step for a post. If all steps are approved, the post proceeds to publishing.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Step approved" }, "400": { "description": "No pending approval step or not authorized to approve" }, "404": { "description": "Post not found" } } } }, "/v1/posts/{id}/reject": { "post": { "tags": [ "Approval Workflows" ], "summary": "Reject post", "description": "Reject the current approval step with a comment.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "comment": { "type": "string", "maxLength": 2000, "description": "Rejection reason" } } } } } }, "responses": { "200": { "description": "Post rejected" }, "400": { "description": "No pending approval step" }, "404": { "description": "Post not found" } } } }, "/v1/posts/{id}/approval-status": { "get": { "tags": [ "Approval Workflows" ], "summary": "Get approval status", "description": "Get the full approval chain status for a post.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Approval chain status", "content": { "application/json": { "schema": { "type": "object", "properties": { "workflowId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "workflowName": { "type": "string" }, "currentStep": { "type": "integer" }, "totalSteps": { "type": "integer" }, "status": { "type": "string", "enum": [ "PENDING", "APPROVED", "REJECTED" ] }, "steps": { "type": "array", "items": { "$ref": "#/components/schemas/ApprovalStepStatus" } } }, "required": [ "workflowId", "workflowName", "currentStep", "totalSteps", "status", "steps" ] } } } }, "404": { "description": "Post not found or no workflow assigned" } } } }, "/v1/workspaces/{id}/custom-domain": { "post": { "tags": [ "Custom Domains" ], "summary": "Set custom domain", "description": "Set a custom domain for the workspace review portal. Agency plan only.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "domain": { "type": "string", "minLength": 4, "maxLength": 253, "description": "Custom domain name", "example": "reviews.youragency.com" } }, "required": [ "domain" ] } } } }, "responses": { "200": { "description": "Custom domain configured", "content": { "application/json": { "schema": { "type": "object", "properties": { "domain": { "type": "string" }, "status": { "type": "string", "enum": [ "PENDING", "VERIFIED", "FAILED" ] }, "verificationToken": { "type": "string" }, "dnsInstructions": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "CNAME" ] }, "name": { "type": "string" }, "value": { "type": "string" }, "txtRecord": { "type": "object", "properties": { "name": { "type": "string" }, "value": { "type": "string" } }, "required": [ "name", "value" ] } }, "required": [ "type", "name", "value", "txtRecord" ] } }, "required": [ "domain", "status", "verificationToken", "dnsInstructions" ] } } } }, "402": { "description": "Agency plan required" }, "409": { "description": "Domain already in use by another workspace" } } }, "delete": { "tags": [ "Custom Domains" ], "summary": "Remove custom domain", "description": "Remove the custom domain from the workspace.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Custom domain removed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "404": { "description": "No custom domain configured" } } } }, "/v1/workspaces/{id}/custom-domain/verify": { "get": { "tags": [ "Custom Domains" ], "summary": "Verify custom domain", "description": "Check DNS propagation and return domain verification status.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Verification status", "content": { "application/json": { "schema": { "type": "object", "properties": { "domain": { "type": "string" }, "status": { "type": "string", "enum": [ "PENDING", "VERIFIED", "FAILED" ] }, "verifiedAt": { "type": "string", "nullable": true, "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "domain", "status", "verifiedAt" ] } } } }, "404": { "description": "No custom domain configured" } } } }, "/v1/workspaces/{id}/usage-report": { "get": { "tags": [ "Usage Reports" ], "summary": "Get usage report", "description": "Get workspace usage data for a date range. Available on all paid plans. Add `Accept: text/csv` header for CSV export.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "description": "Start date (ISO 8601, defaults to 30 days ago)", "example": "2026-02-01" }, "required": false, "name": "from", "in": "query" }, { "schema": { "type": "string", "description": "End date (ISO 8601, defaults to today)", "example": "2026-03-03" }, "required": false, "name": "to", "in": "query" } ], "responses": { "200": { "description": "Usage report data", "content": { "application/json": { "schema": { "type": "object", "properties": { "period": { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } }, "required": [ "from", "to" ] }, "postsPublished": { "type": "integer" }, "postsByPlatform": { "type": "object", "additionalProperties": { "type": "integer" } }, "aiCreditsUsed": { "type": "integer" }, "activeAccounts": { "type": "integer" }, "teamMembers": { "type": "integer" } }, "required": [ "period", "postsPublished", "postsByPlatform", "aiCreditsUsed", "activeAccounts", "teamMembers" ] } } } }, "400": { "description": "Invalid date format or range" }, "402": { "description": "Paid plan required" } } } }, "/v1/pricing/founding-status": { "get": { "tags": [ "Pricing" ], "summary": "Get founding status", "description": "Public endpoint (no auth required). Returns founding window status, days remaining, spots remaining, and pricing for all plans including annual discounts.", "responses": { "200": { "description": "Founding status and pricing", "content": { "application/json": { "schema": { "type": "object", "properties": { "foundingActive": { "type": "boolean", "description": "Whether the founding window is active" }, "windowEnd": { "type": "string", "description": "ISO date when founding window closes" }, "daysRemaining": { "type": "integer", "description": "Days remaining in founding window" }, "spotsRemaining": { "type": "integer", "description": "Founding spots remaining" }, "plans": { "type": "object", "additionalProperties": { "type": "object", "properties": { "standard": { "type": "number", "description": "Standard monthly price" }, "founding": { "type": "number", "description": "Effective monthly rate at founding annual price (display only — founding is annual billing only)" }, "savings": { "type": "number", "description": "Monthly savings vs standard monthly rate" }, "standardAnnual": { "type": "number", "description": "Standard annual price" }, "foundingAnnual": { "type": "number", "description": "Founding annual price" }, "annualSavings": { "type": "number", "description": "Annual savings" } }, "required": [ "standard", "founding", "savings", "standardAnnual", "foundingAnnual", "annualSavings" ] } } }, "required": [ "foundingActive", "windowEnd", "daysRemaining", "spotsRemaining", "plans" ] } } } } } } }, "/v1/analytics/posts": { "get": { "tags": [ "Analytics" ], "summary": "List post metrics across the workspace", "description": "Returns collected engagement metrics for every published post in the workspace, newest collection first, cursor-paginated. Reads stored metrics only — it never triggers a live platform fetch. Use GET /v1/analytics/posts/{postId} or POST /v1/analytics/posts/{postId}/refresh for a fresh pull of a single post.", "parameters": [ { "schema": { "type": "string", "description": "Only include metrics whose period starts on or after this date (ISO 8601 or YYYY-MM-DD)", "example": "2026-05-01" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "description": "Only include metrics whose period ends on or before this date (ISO 8601 or YYYY-MM-DD)", "example": "2026-05-31" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "string", "enum": [ "HOURLY", "DAILY", "WEEKLY", "MONTHLY" ], "description": "Filter to a single granularity. All granularities are returned when omitted.", "example": "DAILY" }, "required": false, "name": "granularity", "in": "query" }, { "schema": { "type": "string", "description": "Comma-separated list of platforms (INSTAGRAM, LINKEDIN, etc.)" }, "required": false, "name": "platforms", "in": "query" }, { "schema": { "type": "string", "description": "Opaque cursor from a previous response's next_cursor" }, "required": false, "name": "cursor", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Paginated post metrics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListPostAnalyticsResponse" } } } } } } }, "/v1/analytics/posts/{postId}": { "get": { "tags": [ "Analytics" ], "summary": "Get metrics for a specific post", "description": "Returns engagement metrics (impressions, reach, likes, comments, shares, clicks, saves) for a post across all platforms it was published to.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "The post ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "postId", "in": "path" }, { "schema": { "type": "string", "format": "date-time", "description": "Start of date range (ISO 8601)", "example": "2024-01-01T00:00:00Z" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "End of date range (ISO 8601)", "example": "2024-01-31T23:59:59Z" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "string", "enum": [ "HOURLY", "DAILY", "WEEKLY", "MONTHLY" ], "default": "DAILY", "description": "Time granularity for metrics aggregation", "example": "DAILY" }, "required": false, "name": "granularity", "in": "query" }, { "schema": { "type": "string", "description": "Comma-separated list of specific metrics to include" }, "required": false, "name": "metrics", "in": "query" } ], "responses": { "200": { "description": "Post metrics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PostMetricsResponse" } } } }, "404": { "description": "Post not found" } } } }, "/v1/analytics/accounts/{accountId}": { "get": { "tags": [ "Analytics" ], "summary": "Get metrics for a specific account", "description": "Returns aggregate metrics and follower stats for a connected social account.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "The social account ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "accountId", "in": "path" }, { "schema": { "type": "string", "format": "date-time", "description": "Start of date range (ISO 8601)", "example": "2024-01-01T00:00:00Z" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "End of date range (ISO 8601)", "example": "2024-01-31T23:59:59Z" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "string", "enum": [ "HOURLY", "DAILY", "WEEKLY", "MONTHLY" ], "default": "DAILY", "description": "Time granularity for metrics aggregation", "example": "DAILY" }, "required": false, "name": "granularity", "in": "query" } ], "responses": { "200": { "description": "Account metrics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountMetrics" } } } }, "404": { "description": "Account not found" } } } }, "/v1/analytics/aggregate": { "get": { "tags": [ "Analytics" ], "summary": "Get aggregate metrics across posts and accounts", "description": "Returns total engagement metrics, top performing posts, and per-platform breakdowns.", "parameters": [ { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "string", "description": "Comma-separated list of account IDs to filter by" }, "required": false, "name": "accountIds", "in": "query" }, { "schema": { "type": "string", "description": "Comma-separated list of platforms (TWITTER, LINKEDIN, etc.)" }, "required": false, "name": "platforms", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 10, "description": "Number of top performing posts to return" }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Aggregate metrics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AggregateMetrics" } } } } } } }, "/v1/analytics/overview": { "get": { "tags": [ "Analytics" ], "summary": "Get workspace-level analytics overview", "description": "Returns a high-level summary of analytics across all accounts and posts.", "parameters": [ { "schema": { "type": "string", "format": "date-time", "description": "Start of date range (ISO 8601)", "example": "2024-01-01T00:00:00Z" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "End of date range (ISO 8601)", "example": "2024-01-31T23:59:59Z" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "string", "enum": [ "HOURLY", "DAILY", "WEEKLY", "MONTHLY" ], "default": "DAILY", "description": "Time granularity for metrics aggregation", "example": "DAILY" }, "required": false, "name": "granularity", "in": "query" } ], "responses": { "200": { "description": "Analytics overview", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyticsOverview" } } } } } } }, "/v1/analytics/posts/{postId}/refresh": { "post": { "tags": [ "Analytics" ], "summary": "Force refresh metrics for a post", "description": "Fetches fresh metrics from all platforms for this post, bypassing the cache.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "postId", "in": "path" } ], "responses": { "200": { "description": "Refreshed metrics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshMetricsResponse" } } } }, "404": { "description": "Post not found" } } } }, "/v1/analytics/accounts/{accountId}/refresh": { "post": { "tags": [ "Analytics" ], "summary": "Force refresh metrics for an account", "description": "Fetches fresh metrics from the platform for this account, bypassing the cache.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "accountId", "in": "path" } ], "responses": { "200": { "description": "Refreshed metrics", "content": { "application/json": { "schema": { "type": "object", "properties": { "accountId": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "platform": { "type": "string", "enum": [ "TWITTER", "LINKEDIN", "INSTAGRAM", "FACEBOOK", "BLUESKY", "TIKTOK", "YOUTUBE", "PINTEREST", "THREADS", "REDDIT", "SNAPCHAT", "TELEGRAM", "GOOGLE_BUSINESS", "MASTODON", "WHATSAPP" ], "description": "Social media platform" }, "followers": { "type": "integer", "minimum": 0, "description": "Current follower count" }, "followersChange": { "type": "integer", "description": "Follower change in period" }, "postsPublished": { "type": "integer", "minimum": 0 }, "periodStart": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "periodEnd": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "dailyMetrics": { "type": "array", "items": { "$ref": "#/components/schemas/PostMetrics" } }, "refreshedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "accountId", "platform", "followers", "followersChange", "postsPublished", "periodStart", "periodEnd", "refreshedAt" ] } } } }, "404": { "description": "Account not found" } } } }, "/v1/audit-logs": { "get": { "tags": [ "Audit Logs" ], "summary": "List audit logs", "description": "List audit logs for the organization with filtering and pagination.\n\nSupports filtering by resource type, action, actor, and date range.\nExport to CSV by setting format=csv.", "parameters": [ { "schema": { "type": "string", "description": "Filter by resource type (e.g., \"posts\", \"accounts\")" }, "required": false, "name": "resourceType", "in": "query" }, { "schema": { "type": "string", "enum": [ "create", "update", "delete" ], "description": "Filter by action type" }, "required": false, "name": "action", "in": "query" }, { "schema": { "type": "string", "description": "Filter by actor (user ID)" }, "required": false, "name": "actorId", "in": "query" }, { "schema": { "type": "string", "enum": [ "user", "api_key", "system" ], "description": "Type of actor who performed the action" }, "required": false, "name": "actorType", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "Filter logs after this date (ISO 8601)" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "Filter logs before this date (ISO 8601)" }, "required": false, "name": "endDate", "in": "query" }, { "schema": { "type": "string", "description": "Cursor for pagination (last audit log ID)" }, "required": false, "name": "cursor", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50, "description": "Number of logs to return (1-100)" }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "enum": [ "json", "csv" ], "default": "json", "description": "Response format" }, "required": false, "name": "format", "in": "query" } ], "responses": { "200": { "description": "List of audit logs", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuditLogListResponse" } }, "text/csv": { "schema": { "type": "string" } } } }, "401": { "description": "Authentication required" }, "429": { "description": "Rate limit exceeded (30 requests per minute)" } } } }, "/v1/audit-logs/stats": { "get": { "tags": [ "Audit Logs" ], "summary": "Get audit log statistics", "description": "Get summary statistics of audit logs. Useful for dashboards and monitoring.", "parameters": [ { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "startDate", "in": "query" }, { "schema": { "type": "string", "format": "date-time" }, "required": false, "name": "endDate", "in": "query" } ], "responses": { "200": { "description": "Audit log statistics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuditLogStatsResponse" } } } } } } }, "/v1/audit-logs/{id}": { "get": { "tags": [ "Audit Logs" ], "summary": "Get a specific audit log entry", "description": "Retrieve a single audit log entry by ID.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Audit log entry", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AuditLog" } }, "required": [ "data" ] } } } }, "404": { "description": "Audit log not found" } } } }, "/v1/billing/current": { "get": { "tags": [ "Billing" ], "summary": "Get current billing state", "description": "Returns the live Stripe-authoritative subscription state for the workspace, including trial countdown fields.", "responses": { "200": { "description": "Current billing state", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BillingCurrent" } } } }, "503": { "description": "Billing not configured - Stripe integration unavailable" } } } }, "/v1/billing/plans": { "get": { "tags": [ "Billing" ], "summary": "Get available pricing plans", "description": "Returns all available subscription plans with pricing and limits.", "responses": { "200": { "description": "List of pricing plans", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlansResponse" } } } } } } }, "/v1/billing/checkout": { "post": { "tags": [ "Billing" ], "summary": "Create a checkout session", "description": "Create a Stripe checkout session for plan upgrade.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckoutRequest" } } } }, "responses": { "200": { "description": "Checkout session created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckoutSession" } } } }, "400": { "description": "Invalid request or billing not configured" }, "503": { "description": "Billing not configured - Stripe integration unavailable" } } } }, "/v1/billing/portal": { "get": { "tags": [ "Billing" ], "summary": "Get customer portal URL", "description": "Get a Stripe customer portal link for subscription management.", "parameters": [ { "schema": { "type": "string", "format": "uri" }, "required": true, "name": "returnUrl", "in": "query" } ], "responses": { "200": { "description": "Portal URL", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PortalResponse" } } } }, "400": { "description": "Invalid request" }, "503": { "description": "Billing not configured" } } }, "post": { "tags": [ "Billing" ], "summary": "Create a customer portal session", "description": "Create a Stripe customer portal session for subscription management.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PortalRequest" } } } }, "responses": { "200": { "description": "Portal URL", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PortalResponse" } } } }, "400": { "description": "Invalid request" }, "503": { "description": "Billing not configured" } } } }, "/v1/billing/subscription": { "get": { "tags": [ "Billing" ], "summary": "Get current subscription", "description": "Get current subscription info including plan, status, and limits.", "responses": { "200": { "description": "Subscription details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Subscription" } } } } } } }, "/v1/billing/usage": { "get": { "tags": [ "Billing" ], "summary": "Get current usage", "description": "Get current usage vs limits for the workspace.", "responses": { "200": { "description": "Usage details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageResponse" } } } }, "500": { "description": "Failed to fetch usage data" } } } }, "/v1/billing/cancel": { "post": { "tags": [ "Billing" ], "summary": "Cancel subscription", "description": "Cancel subscription at period end.", "responses": { "200": { "description": "Subscription will be cancelled at period end", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] }, "message": { "type": "string" } }, "required": [ "success", "message" ] } } } }, "400": { "description": "Failed to cancel subscription" }, "503": { "description": "Billing not configured" } } } }, "/v1/billing/resume": { "post": { "tags": [ "Billing" ], "summary": "Resume subscription", "description": "Resume a cancelled subscription.", "responses": { "200": { "description": "Subscription resumed", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] }, "message": { "type": "string" } }, "required": [ "success", "message" ] } } } }, "400": { "description": "Failed to resume subscription" }, "503": { "description": "Billing not configured" } } } }, "/v1/inbox/comments": { "get": { "tags": [ "Inbox" ], "summary": "List all comments", "description": "List all comments across all accounts for the workspace.", "parameters": [ { "schema": { "type": "string", "description": "Filter by platform" }, "required": false, "name": "platform", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "Filter comments created after this date" }, "required": false, "name": "since", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ], "description": "Filter by replied status" }, "required": false, "name": "replied", "in": "query" }, { "schema": { "type": "boolean", "nullable": true, "description": "Controls visibility of soft-hidden comments. Omitted or false returns only non-hidden comments; true returns only hidden comments. The filter is binary — there is no value that returns both. A full sync requires two requests." }, "required": false, "name": "hiddenOnly", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "List of comments", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommentListResponse" } } } } } } }, "/v1/inbox/comments/stats": { "get": { "tags": [ "Inbox" ], "summary": "Get comment statistics", "description": "Get comment statistics for the workspace.", "responses": { "200": { "description": "Comment statistics", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommentStats" } } } } } } }, "/v1/inbox/comments/{commentId}": { "get": { "tags": [ "Inbox" ], "summary": "Get a single comment", "description": "Get a single comment by ID.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "commentId", "in": "path" } ], "responses": { "200": { "description": "Comment details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Comment" } } } }, "404": { "description": "Comment not found" } } } }, "/v1/inbox/comments/{commentId}/reply": { "post": { "tags": [ "Inbox" ], "summary": "Reply to a comment", "description": "Reply to a comment on the social platform.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "commentId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyToCommentRequest" } } } }, "responses": { "200": { "description": "Reply posted successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReplyResponse" } } } }, "400": { "description": "Failed to reply" }, "404": { "description": "Comment not found" } } } }, "/v1/inbox/comments/{commentId}/mark-replied": { "post": { "tags": [ "Inbox" ], "summary": "Mark comment as replied", "description": "Mark a comment as replied (manual marking without sending a reply).", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "commentId", "in": "path" } ], "responses": { "200": { "description": "Comment marked as replied", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Comment" } } } }, "404": { "description": "Comment not found" } } }, "delete": { "tags": [ "Inbox" ], "summary": "Unmark comment as replied", "description": "Unmark a comment as replied (undo).", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "commentId", "in": "path" } ], "responses": { "200": { "description": "Comment unmarked as replied", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Comment" } } } }, "404": { "description": "Comment not found" } } } }, "/v1/inbox/comments/{commentId}/hide": { "post": { "tags": [ "Inbox" ], "summary": "Hide a comment", "description": "Soft-hide a comment. The comment is retained and is not deleted from VoxBurst or the source platform — it is only excluded from the default inbox list.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "commentId", "in": "path" } ], "responses": { "200": { "description": "Comment hidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HideCommentResponse" } } } }, "404": { "description": "Comment not found" } } }, "delete": { "tags": [ "Inbox" ], "summary": "Unhide a comment", "description": "Reverse a hide, returning the comment to the default inbox list.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "commentId", "in": "path" } ], "responses": { "200": { "description": "Comment unhidden", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HideCommentResponse" } } } }, "404": { "description": "Comment not found" } } } }, "/v1/inbox/sync": { "post": { "tags": [ "Inbox" ], "summary": "Sync all comments", "description": "Manually trigger a sync of comments for all accounts.", "responses": { "200": { "description": "Sync completed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SyncCommentsResponse" } } } } } } }, "/v1/inbox/accounts/{accountId}/comments": { "get": { "tags": [ "Inbox" ], "summary": "Get comments for an account", "description": "Get comments for a specific social account.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "accountId", "in": "path" }, { "schema": { "type": "string", "description": "Filter by platform" }, "required": false, "name": "platform", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "Filter comments created after this date" }, "required": false, "name": "since", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ], "description": "Filter by replied status" }, "required": false, "name": "replied", "in": "query" }, { "schema": { "type": "boolean", "nullable": true, "description": "Controls visibility of soft-hidden comments. Omitted or false returns only non-hidden comments; true returns only hidden comments. The filter is binary — there is no value that returns both. A full sync requires two requests." }, "required": false, "name": "hiddenOnly", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "List of comments", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommentListResponse" } } } }, "404": { "description": "Account not found" } } } }, "/v1/inbox/accounts/{accountId}/comments/sync": { "post": { "tags": [ "Inbox" ], "summary": "Sync comments for an account", "description": "Sync comments for a specific social account.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "accountId", "in": "path" } ], "responses": { "200": { "description": "Sync completed", "content": { "application/json": { "schema": { "type": "object", "properties": { "synced": { "type": "integer" }, "errors": { "type": "array", "items": { "type": "string" } } }, "required": [ "synced", "errors" ] } } } }, "404": { "description": "Account not found" } } } }, "/v1/inbox/posts/{postId}/comments": { "get": { "tags": [ "Inbox" ], "summary": "Get comments for a post", "description": "Get comments for a specific post.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "postId", "in": "path" }, { "schema": { "type": "string", "description": "Filter by platform" }, "required": false, "name": "platform", "in": "query" }, { "schema": { "type": "string", "format": "date-time", "description": "Filter comments created after this date" }, "required": false, "name": "since", "in": "query" }, { "schema": { "type": "string", "enum": [ "true", "false" ], "description": "Filter by replied status" }, "required": false, "name": "replied", "in": "query" }, { "schema": { "type": "boolean", "nullable": true, "description": "Controls visibility of soft-hidden comments. Omitted or false returns only non-hidden comments; true returns only hidden comments. The filter is binary — there is no value that returns both. A full sync requires two requests." }, "required": false, "name": "hiddenOnly", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string" }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "List of comments", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommentListResponse" } } } }, "404": { "description": "Post not found" } } } }, "/v1/invitations": { "get": { "tags": [ "Invitations" ], "summary": "List pending invitations", "description": "Lists pending invitations for the current user.", "responses": { "200": { "description": "List of pending invitations", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListInvitationsResponse" } } } }, "401": { "description": "Authentication required" } } }, "post": { "tags": [ "Invitations" ], "summary": "Send an invitation", "description": "Sends an invitation to join a workspace.\n\nRequirements:\n- Inviter must be ADMIN or OWNER of the workspace\n- Cannot invite someone who is already a member\n- Cannot invite as OWNER\n- Checks team member limits based on plan", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendInviteRequest" } } } }, "responses": { "201": { "description": "Invitation sent successfully", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendInviteResponse" } } } }, "400": { "description": "Validation error" }, "402": { "description": "Plan limit exceeded" }, "403": { "description": "Only admins and owners can invite members" }, "409": { "description": "User already invited or member" } } } }, "/v1/invitations/{token}": { "get": { "tags": [ "Invitations" ], "summary": "Get invitation details", "description": "Gets invitation details by token. Used by the accept invitation page.", "parameters": [ { "schema": { "type": "string", "description": "Invitation token" }, "required": true, "name": "token", "in": "path" } ], "responses": { "200": { "description": "Invitation details", "content": { "application/json": { "schema": { "anyOf": [ { "$ref": "#/components/schemas/GetInvitationResponse" }, { "$ref": "#/components/schemas/GetAcceptedInvitationResponse" }, { "$ref": "#/components/schemas/GetExpiredInvitationResponse" } ] } } } }, "400": { "description": "Invalid invitation token" } } } }, "/v1/invitations/{token}/accept": { "post": { "tags": [ "Invitations" ], "summary": "Accept an invitation", "description": "Accepts an invitation and joins the workspace.\n\nRequirements:\n- User must be authenticated\n- User's email must match the invitation email\n- Invitation must be in PENDING status", "parameters": [ { "schema": { "type": "string" }, "required": true, "name": "token", "in": "path" } ], "responses": { "200": { "description": "Invitation accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AcceptInviteResponse" } } } }, "400": { "description": "Invitation expired or invalid" }, "403": { "description": "Email mismatch" }, "409": { "description": "Already a member or invitation already accepted" } } } }, "/v1/invitations/{id}": { "delete": { "tags": [ "Invitations" ], "summary": "Revoke/decline an invitation", "description": "Revokes a pending invitation.\n\nCan be done by:\n- The invitee (declining their own invitation)\n- An admin/owner of the workspace (revoking the invitation)", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Invitation revoked/declined", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RevokeInviteResponse" } } } }, "403": { "description": "Permission denied" }, "404": { "description": "Invitation not found" } } } }, "/v1/workspaces/{id}/invitations/{invitationId}/resend": { "post": { "tags": [ "Invitations", "Workspaces" ], "summary": "Resend an invitation", "description": "Resends a pending invitation email. Requires ADMIN or OWNER role.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Workspace ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "invitationId", "in": "path" } ], "responses": { "200": { "description": "Invitation resent", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "400": { "description": "Can only resend pending invitations" }, "403": { "description": "Only admins and owners can resend invitations" }, "404": { "description": "Invitation not found" } } } }, "/v1/platforms": { "get": { "tags": [ "Platforms" ], "summary": "List all platforms", "description": "Get information about all supported social media platforms.", "responses": { "200": { "description": "List of platforms", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlatformListResponse" } } } } } } }, "/v1/platforms/capabilities": { "get": { "tags": [ "Platforms" ], "summary": "Get content limits and validation rules", "description": "Get content limits and validation rules for all platforms.\n\nReturns detailed limits useful for building content editors:\n- Character limits\n- Media limits (count, size, duration)\n- Hashtag limits\n- Feature support (links, first comment, etc.)\n\n## Platform Capabilities Quick Reference\n\n| Platform | Chars | Images | Videos | Hashtags | Links | First Comment |\n|----------|-------|--------|--------|----------|-------|---------------|\n| Twitter/X | 280 | 4 × 5MB | 1 × 512MB (2:20) | 1–3 rec. | ✅ (23 chars) | ❌ |\n| LinkedIn | 3,000 | 9 × 8MB | 1 × 5GB (10 min) | 3–5 rec. | ✅ | ✅ |\n| Instagram | 2,200 | 10 × 8MB JPEG | 10 × 100MB (60s) | max 30 | ❌ | ✅ |\n| Facebook | 63,206 | 10 × 30MB | 1 × 4GB (4 hrs) | 0–3 rec. | ✅ | ✅ |\n| Threads | 500 | 10 × 8MB | 1 × 100MB (5 min) | 1–5 rec. | ✅ | ✅ |\n| Bluesky | 300 | 4 × 1MB | ❌ | 1–3 rec. | ✅ | ❌ |\n| TikTok | 2,200 | 35 × 20MB | 1 × 287MB (10 min) | 3–5 rec. | ❌ | ✅ |\n| YouTube | 5,000 | thumbnails only | 1 × 256GB (12 hrs) | max 15 | ✅ | ✅ |\n| Pinterest | 500 | 5 × 32MB | 1 × 2GB (15 min) | 2–5 rec. | ✅ | ❌ |\n| Reddit | 40,000 | 20 × 20MB | 1 × 1GB (15 min) | ❌ | ✅ | ✅ |\n| Snapchat | 80 | 1 × 5MB | 1 × 100MB (60s) | ❌ | ✅ | ❌ |\n| Google Business | 1,500 | 10 × 25MB | 1 × 100MB (30s) | ❌ | ✅ (CTA) | ❌ |\n| Mastodon | 500* | 4 × 16MB | 1 × 100MB (5 min) | 1–5 rec. | ✅ | ❌ |\n\n## Detailed Platform Specifications\n\n### Twitter/X\n| Spec | Value |\n|------|-------|\n| Character limit | 280 characters |\n| URL handling | All URLs count as exactly 23 characters |\n| Images | Up to 4 images, 5MB max each |\n| Videos | 1 video, 512MB max, 2 min 20 sec duration |\n| GIFs | 1 animated GIF, 15MB max |\n| Media mixing | Cannot mix images and video in same post |\n| Hashtags | No hard limit; 1–3 recommended |\n| Links | Clickable with preview cards |\n| First comment | Not supported |\n| Rate limit | 300 tweets per 3 hours |\n\n### LinkedIn\n| Spec | Value |\n|------|-------|\n| Character limit | 3,000 characters |\n| Images | Up to 9 images, 8MB max each |\n| Videos | 1 video, 5GB max, 10 minutes max |\n| PDF documents | Supported as native document posts |\n| Media mixing | Cannot mix images and video |\n| Hashtags | Soft limit 30; 3–5 optimal |\n| Mentions | Up to 100 per post |\n| Links | Clickable with previews |\n| First comment | ✅ Supported |\n| Organization posting | Use `organization` param |\n\n### Instagram\n| Spec | Value |\n|------|-------|\n| Character limit | 2,200 characters |\n| Images | Up to 10 images, 8MB max, **JPEG only** |\n| Videos | Up to 10 videos, 100MB max, 60 sec each |\n| Carousels | Up to 10 slides, can mix images/video |\n| Aspect ratios | 1.91:1 (landscape) to 4:5 (portrait) |\n| Hashtags | Hard limit 30; 5–15 recommended |\n| Mentions | Up to 20 per post |\n| Links | **NOT clickable in captions** |\n| First comment | ✅ Supported with delay |\n| Publishing | Container-based (async) |\n| Rate limit | 100 posts per 24 hours |\n\n### Facebook\n| Spec | Value |\n|------|-------|\n| Character limit | 63,206 characters |\n| Images | Up to 10 images, 30MB max each |\n| Videos | 1 video, 4GB max, 4 hours max |\n| GIFs | 1 animated GIF supported |\n| Hashtags | No hard limit; 0–3 recommended |\n| Links | Clickable with preview cards |\n| First comment | ✅ Supported |\n| Page selection | Required for multi-page accounts |\n| Rate limit | ~60 posts per hour per Page |\n\n### Threads\n| Spec | Value |\n|------|-------|\n| Character limit | 500 characters |\n| Images | Up to 10 images, 8MB max each |\n| Videos | 1 video, 100MB max, 5 minutes max |\n| Carousels | Supported, can mix images/video |\n| Hashtags | No hard limit; 1–5 recommended |\n| Links | Clickable with previews |\n| First comment | ✅ Supported |\n| Publishing | Container-based, 30 sec timeout |\n\n### Bluesky\n| Spec | Value |\n|------|-------|\n| Character limit | 300 characters |\n| Images | Up to 4 images, **1MB max each** |\n| Videos | ❌ Not yet supported |\n| GIFs | 1 animated GIF supported |\n| Hashtags | No hard limit; 1–3 recommended |\n| Links | Clickable with card embeds |\n| First comment | ❌ Not supported |\n| Protocol | AT Protocol (decentralized) |\n\n### TikTok\n| Spec | Value |\n|------|-------|\n| Character limit | 2,200 characters |\n| Images | 35 images in Photo Mode, 20MB max each |\n| Videos | 1 video, 287MB max, 10 minutes max |\n| Aspect ratio | 9:16 vertical recommended |\n| Hashtags | Hard limit 100; **3–5 trending recommended** |\n| Links | **NOT clickable in captions** |\n| First comment | ✅ Supported |\n| Rate limit | ~20 posts per day |\n\n### YouTube\n| Spec | Value |\n|------|-------|\n| Character limit | 5,000 (description), 100 (title) |\n| Images | Thumbnails only |\n| Videos | 1 video, 256GB max, 12 hours max |\n| Aspect ratio | 16:9 recommended |\n| Hashtags | Hard limit 15; **first 3 appear above title** |\n| Links | Clickable in description |\n| First comment | ✅ Supported (can be pinned) |\n| Rate limit | 10/day (unverified), 100/day (verified) |\n\n### Pinterest\n| Spec | Value |\n|------|-------|\n| Character limit | 500 characters |\n| Images | Up to 5 images, 32MB max each |\n| Videos | 1 video, 2GB max, 15 minutes max |\n| Aspect ratio | **2:3 vertical performs best** |\n| Hashtags | Up to 20; 2–5 recommended |\n| Links | **Destination URL critical** |\n| First comment | ❌ Not supported |\n| Rate limit | ~100 pins per day |\n\n### Reddit\n| Spec | Value |\n|------|-------|\n| Character limit | 40,000 characters |\n| Images | Up to 20 images, 20MB max each |\n| Videos | 1 video, 1GB max, 15 minutes max |\n| Hashtags | **❌ Reddit does NOT use hashtags** |\n| Links | Clickable with previews |\n| First comment | ✅ Supported |\n| Rate limits | Subreddit-specific (1–10 posts/hour) |\n\n### Snapchat\n| Spec | Value |\n|------|-------|\n| Character limit | **80 characters only** |\n| Images | 1 image, 5MB max |\n| Videos | 1 video, 100MB max, 60 seconds max |\n| Aspect ratio | **9:16 vertical required** |\n| Hashtags | ❌ Not supported |\n| Links | Swipe-up for Spotlight/Ads |\n| First comment | ❌ Not supported |\n\n### Google Business Profile\n| Spec | Value |\n|------|-------|\n| Character limit | 1,500 characters |\n| Images | Up to 10 images, 25MB max, min 250×250px |\n| Videos | 1 video, 100MB max, 30 seconds max |\n| Hashtags | ❌ Not supported |\n| Links | **CTA buttons supported** (Learn More, Buy, etc.) |\n| Post types | What's New, Event, Offer, Product |\n| First comment | ❌ Not supported |\n| Rate limit | ~5 posts per day per location |\n\n### Mastodon\n| Spec | Value |\n|------|-------|\n| Character limit | **500 default (varies 500–5,000 by instance)** |\n| Images | Up to 4 images, 16MB max each |\n| Videos | 1 video, 100MB max, 5 minutes max |\n| Hashtags | 1–5 recommended; **use CamelCase** |\n| Links | Clickable with Open Graph cards |\n| Content warnings | ✅ Supported |\n| First comment | ❌ Not supported |\n| Rate limit | ~300 posts per 5 minutes |\n", "responses": { "200": { "description": "Platform capabilities", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlatformCapabilitiesResponse" } } } } } } }, "/v1/platforms/{platform}/capabilities": { "get": { "tags": [ "Platforms" ], "summary": "Get content limits for a specific platform", "description": "Get content limits for a specific platform.", "parameters": [ { "schema": { "type": "string", "description": "Platform key (e.g., twitter, linkedin)" }, "required": true, "name": "platform", "in": "path" } ], "responses": { "200": { "description": "Platform capabilities", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlatformSpecificCapability" } } } }, "404": { "description": "Platform not found" } } } }, "/v1/platforms/managed-oauth": { "get": { "tags": [ "Platforms" ], "summary": "Get OAuth availability status", "description": "Get OAuth availability status for all platforms.\n\nA platform is marked available if EITHER:\n1. A managed OAuth app is enabled for it, OR\n2. Platform-level OAuth credentials are configured", "responses": { "200": { "description": "OAuth availability by platform", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ManagedOAuthResponse" } } } }, "500": { "description": "Failed to list managed OAuth status" } } } }, "/v1/platforms/{platform}": { "get": { "tags": [ "Platforms" ], "summary": "Get platform info", "description": "Get information about a specific platform.", "parameters": [ { "schema": { "type": "string", "description": "Platform key" }, "required": true, "name": "platform", "in": "path" } ], "responses": { "200": { "description": "Platform details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlatformDetailResponse" } } } }, "404": { "description": "Platform not found" } } } }, "/v1/platforms/{platform}/managed-oauth": { "get": { "tags": [ "Platforms" ], "summary": "Check managed OAuth availability", "description": "Check if managed OAuth is available for a specific platform.", "parameters": [ { "schema": { "type": "string", "description": "Platform key" }, "required": true, "name": "platform", "in": "path" } ], "responses": { "200": { "description": "Managed OAuth status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlatformManagedOAuthResponse" } } } }, "404": { "description": "Platform not found" }, "500": { "description": "Failed to check managed OAuth status" } } } }, "/v1/accounts/{id}/queue": { "get": { "tags": [ "Queue" ], "summary": "Get queue configuration and preview", "description": "Returns the queue configuration (time slots) and a preview of upcoming scheduled posts.\nUse this to display a visual queue calendar/timeline in the UI.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "The social account ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 60, "default": 14, "description": "Number of days to include in the preview" }, "required": false, "name": "days", "in": "query" } ], "responses": { "200": { "description": "Queue configuration and preview", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QueuePreviewResponse" } } } }, "404": { "description": "Account not found" } } }, "post": { "tags": [ "Queue" ], "summary": "Set queue time slots", "description": "Configure the time slots when posts should be published.\nThis replaces all existing slots with the new configuration.\n\nExample: To post every weekday at 9am and 2pm:\n```json\n{\n \"timezone\": \"America/New_York\",\n \"slots\": [\n {\"day\": \"monday\", \"hour\": 9, \"minute\": 0},\n {\"day\": \"monday\", \"hour\": 14, \"minute\": 0},\n {\"day\": \"tuesday\", \"hour\": 9, \"minute\": 0},\n ...\n ]\n}\n```", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "The social account ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QueueSlotConfig" } } } }, "responses": { "200": { "description": "Queue configuration updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/QueueConfig" } } } }, "400": { "description": "Invalid slot configuration" }, "404": { "description": "Account not found" } } } }, "/v1/accounts/{id}/queue/reorder": { "post": { "tags": [ "Queue" ], "summary": "Reorder queued posts", "description": "Change the order of posts in the queue. Posts will be reassigned\nto time slots based on their new positions.\n\nUseful for drag-and-drop reordering in the UI.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "The social account ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReorderQueueRequest" } } } }, "responses": { "200": { "description": "Queue reordered successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "404": { "description": "Account not found" } } } }, "/v1/accounts/{id}/queue/posts/{postId}": { "delete": { "tags": [ "Queue" ], "summary": "Remove a post from the queue", "description": "Removes a post from the queue and returns it to draft status.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "The social account ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "format": "uuid", "description": "The post ID to remove from queue", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "postId", "in": "path" } ], "responses": { "200": { "description": "Post removed from queue", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "404": { "description": "Account or post not found" } } } }, "/v1/users/me": { "get": { "tags": [ "Users" ], "summary": "Get current user profile", "description": "Get the current authenticated user's profile and workspace memberships.", "responses": { "200": { "description": "User profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserProfileResponse" } } } }, "401": { "description": "Authentication required" }, "404": { "description": "User not found" } } }, "patch": { "tags": [ "Users" ], "summary": "Update current user profile", "description": "Update the current user's profile information.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateProfileRequest" } } } }, "responses": { "200": { "description": "Profile updated", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique identifier (UUID)", "example": "550e8400-e29b-41d4-a716-446655440000" }, "email": { "type": "string", "format": "email" }, "name": { "type": "string", "nullable": true }, "avatarUrl": { "type": "string", "nullable": true, "format": "uri" }, "createdAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" }, "updatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime string", "example": "2024-02-26T12:00:00.000Z" } }, "required": [ "id", "email", "name", "avatarUrl", "createdAt", "updatedAt" ] } } } }, "400": { "description": "Validation error" }, "401": { "description": "Authentication required" } } }, "delete": { "tags": [ "Users" ], "summary": "Delete current user account", "description": "Delete the current user account.\n\nCannot delete if:\n- User is a system administrator\n- User is the sole owner of any workspaces", "responses": { "200": { "description": "Account deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteAccountResponse" } } } }, "400": { "description": "Cannot delete account (sole owner of workspaces or system admin)" }, "401": { "description": "Authentication required" } } } }, "/v1/users/me/workspaces": { "get": { "tags": [ "Users" ], "summary": "List user's workspaces", "description": "List all workspaces the current user is a member of.", "responses": { "200": { "description": "List of workspaces", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserWorkspaceListResponse" } } } }, "401": { "description": "Authentication required" } } }, "post": { "tags": [ "Users" ], "summary": "Create a new workspace", "description": "Create a new workspace with the current user as owner.", "requestBody": { "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/CreateWorkspaceRequest" }, { "properties": { "name": { "type": "string", "minLength": 2, "maxLength": 100, "description": "Workspace name", "example": "My Company" }, "slug": { "type": "string", "minLength": 2, "maxLength": 50, "pattern": "^[a-z0-9-]+$", "description": "Workspace URL slug", "example": "my-company" }, "logo": { "type": "string", "maxLength": 500, "format": "uri", "description": "Workspace logo URL" } }, "required": [ "name", "slug" ] } ] } } } }, "responses": { "201": { "description": "Workspace created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatedWorkspaceResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Authentication required" }, "409": { "description": "Workspace slug already taken" } } } }, "/v1/workspaces/{id}/members/{userId}": { "patch": { "tags": [ "Workspace Members", "Workspaces" ], "summary": "Update member role", "description": "Update the role of a workspace member.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Workspace ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "format": "uuid", "description": "User ID of the member", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "userId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateRoleRequest" } } } }, "responses": { "200": { "description": "Role updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemberResponse" } } } }, "400": { "description": "Invalid role" }, "401": { "description": "Authentication required" }, "403": { "description": "Cannot change role of owners or change to owner" }, "404": { "description": "Member not found" } } }, "delete": { "tags": [ "Workspace Members", "Workspaces" ], "summary": "Remove a member", "description": "Remove a member from the workspace.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Workspace ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "format": "uuid", "description": "User ID of the member to remove", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "userId", "in": "path" } ], "responses": { "200": { "description": "Member removed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RemoveMemberResponse" } } } }, "401": { "description": "Authentication required" }, "403": { "description": "Cannot remove owners" }, "404": { "description": "Member not found" } } } }, "/v1/workspaces/{id}/members/accept": { "post": { "tags": [ "Workspace Members", "Workspaces" ], "summary": "Accept an invitation", "description": "Accept a pending invitation to join the workspace.", "parameters": [ { "schema": { "type": "string", "format": "uuid", "description": "Workspace ID", "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Invitation accepted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MemberResponse" } } } }, "401": { "description": "Authentication required" }, "404": { "description": "No pending invitation found" } } } }, "/v1/contacts": { "get": { "tags": [ "Contacts" ], "summary": "List contacts", "description": "Paginated list of messaging contacts for the workspace, with optional search, platform, and tag filters. Each contact includes derived messaging-status fields.", "parameters": [ { "schema": { "type": "string", "description": "Case-insensitive search across displayName and username" }, "required": false, "name": "search", "in": "query" }, { "schema": { "allOf": [ { "$ref": "#/components/schemas/Platform" }, { "description": "Filter by platform" } ] }, "required": false, "name": "platform", "in": "query" }, { "schema": { "type": "string", "description": "Comma-separated list of tags. Matches contacts having any of them.", "example": "vip,newsletter" }, "required": false, "name": "tags", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "default": 1 }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Paginated list of contacts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactListResponse" } } } }, "400": { "description": "Invalid query parameters" }, "401": { "description": "Unauthorized" } } }, "post": { "tags": [ "Contacts" ], "summary": "Create a contact", "description": "Create a contact manually. Idempotent on (workspace, platform, platformId) — an existing contact is updated rather than duplicated.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateContactRequest" } } } }, "responses": { "201": { "description": "Contact created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" } } } }, "/v1/contacts/{id}": { "get": { "tags": [ "Contacts" ], "summary": "Get a contact", "description": "Get a single contact with messaging status, recent deliveries, and recent sequence enrollments.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Contact details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactResponse" } } } }, "401": { "description": "Unauthorized" }, "404": { "description": "Contact not found" } } }, "patch": { "tags": [ "Contacts" ], "summary": "Update a contact", "description": "Update displayName, tags, and/or customFields. At least one field must be provided. Returns the full contact detail shape.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateContactRequest" } } } }, "responses": { "200": { "description": "Updated contact", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactResponse" } } } }, "400": { "description": "Validation error — no fields provided" }, "401": { "description": "Unauthorized" }, "404": { "description": "Contact not found" } } }, "delete": { "tags": [ "Contacts" ], "summary": "Delete a contact", "description": "Permanently delete a contact and its delivery/enrollment history.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Contact deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "enum": [ true ] } }, "required": [ "ok" ] } } } }, "401": { "description": "Unauthorized" }, "404": { "description": "Contact not found" } } } }, "/v1/contacts/{id}/tags": { "post": { "tags": [ "Contacts" ], "summary": "Add a tag to a contact", "description": "Add a single tag. No-op if the contact already has the tag.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddContactTagRequest" } } } }, "responses": { "200": { "description": "Updated contact", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "404": { "description": "Contact not found" } } } }, "/v1/contacts/{id}/tags/{tag}": { "delete": { "tags": [ "Contacts" ], "summary": "Remove a tag from a contact", "description": "Remove a single tag. No-op if the contact does not have the tag.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "description": "Tag to remove", "example": "vip" }, "required": true, "name": "tag", "in": "path" } ], "responses": { "200": { "description": "Updated contact", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ContactResponse" } } } }, "401": { "description": "Unauthorized" }, "404": { "description": "Contact not found" } } } }, "/v1/contacts/{id}/messages": { "post": { "tags": [ "Contacts" ], "summary": "Send a direct message to a contact", "description": "Send a one-off direct message. Eligibility is enforced server-side: a contact who has opted out, or whose Meta 24-hour messaging window has closed, is refused with a 400. A transport failure still returns 200 with the recorded delivery so the client can surface `delivery.errorCode` alongside the history entry.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendContactMessageRequest" } } } }, "responses": { "200": { "description": "Message attempted — inspect delivery.status and delivery.errorCode", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendContactMessageResponse" } } } }, "400": { "description": "Validation error, or the send was refused (contact opted out, or the Meta 24-hour messaging window is closed)" }, "401": { "description": "Unauthorized" }, "404": { "description": "Contact not found" } } } }, "/v1/broadcasts": { "get": { "tags": [ "Broadcasts" ], "summary": "List broadcasts", "description": "Paginated list of DM broadcasts for the workspace, newest first.", "parameters": [ { "schema": { "$ref": "#/components/schemas/BroadcastStatus" }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "default": 1 }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Paginated list of broadcasts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BroadcastListResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" } } }, "post": { "tags": [ "Broadcasts" ], "summary": "Create a broadcast", "description": "Create a broadcast in DRAFT status. Nothing is sent until POST /v1/broadcasts/{id}/send.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBroadcastRequest" } } } }, "responses": { "201": { "description": "Broadcast created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BroadcastResponse" } } } }, "400": { "description": "Validation error — including a socialAccountId that is not in this workspace or does not match the selected platforms" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" } } } }, "/v1/broadcasts/preview-count": { "post": { "tags": [ "Broadcasts" ], "summary": "Preview eligible contact count", "description": "Read-only count of contacts that would receive a broadcast for the given platform/account/tag selection. Uses the same eligibility resolution as the real send, so the preview never drifts from what is actually delivered.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BroadcastPreviewCountRequest" } } } }, "responses": { "200": { "description": "Eligible contact count", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BroadcastPreviewCountResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" } } } }, "/v1/broadcasts/{id}": { "get": { "tags": [ "Broadcasts" ], "summary": "Get a broadcast", "description": "Get a single broadcast together with a delivery-status breakdown.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Broadcast with delivery stats", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BroadcastDetailResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Broadcast not found" } } }, "patch": { "tags": [ "Broadcasts" ], "summary": "Update a broadcast", "description": "Update a broadcast. Only DRAFT or SCHEDULED broadcasts can be edited.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateBroadcastRequest" } } } }, "responses": { "200": { "description": "Updated broadcast", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BroadcastResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Broadcast not found" }, "422": { "description": "BROADCAST_NOT_EDITABLE — only DRAFT or SCHEDULED broadcasts can be edited" } } }, "delete": { "tags": [ "Broadcasts" ], "summary": "Delete a broadcast", "description": "Delete a broadcast. Only DRAFT, FAILED, or SENT broadcasts can be deleted.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Broadcast deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Broadcast not found" }, "422": { "description": "BROADCAST_NOT_DELETABLE — only DRAFT, FAILED, or SENT broadcasts can be deleted" } } } }, "/v1/broadcasts/{id}/retry": { "post": { "tags": [ "Broadcasts" ], "summary": "Retry failed deliveries", "description": "Reset FAILED deliveries on a FAILED or SENT broadcast back to PENDING and re-enqueue them. The broadcast returns to SENDING.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Failed deliveries re-enqueued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RetryBroadcastResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Broadcast not found" }, "422": { "description": "BROADCAST_NOT_RETRYABLE (not FAILED or SENT) or NO_FAILED_DELIVERIES (nothing to retry)" } } } }, "/v1/broadcasts/{id}/send": { "post": { "tags": [ "Broadcasts" ], "summary": "Send a broadcast", "description": "Resolve eligible contacts, create PENDING deliveries, and enqueue them. Moves the broadcast to SCHEDULED when `scheduledFor` is set, otherwise SENDING. The opt-in gate is always enforced.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Broadcast enqueued", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendBroadcastResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Broadcast not found" }, "422": { "description": "BROADCAST_ALREADY_SENT (not DRAFT or SCHEDULED), NO_ELIGIBLE_CONTACTS, or BROADCAST_CONTACT_LIMIT_EXCEEDED (audience over 50,000 contacts)" } } } }, "/v1/broadcasts/{id}/deliveries": { "get": { "tags": [ "Broadcasts" ], "summary": "List broadcast deliveries", "description": "Paginated per-contact delivery records for a broadcast, oldest first.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "default": 1 }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Paginated list of deliveries", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BroadcastDeliveryListResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Broadcasts require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Broadcast not found" } } } }, "/v1/sequences": { "get": { "tags": [ "Sequences" ], "summary": "List sequences", "description": "Paginated list of sequences for the workspace, newest first. ARCHIVED sequences are excluded.", "parameters": [ { "schema": { "type": "integer", "minimum": 1, "default": 1 }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Paginated list of sequences", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceListResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" } } }, "post": { "tags": [ "Sequences" ], "summary": "Create a sequence", "description": "Create a sequence in DRAFT status. Add steps before activating it.", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSequenceRequest" } } } }, "responses": { "201": { "description": "Sequence created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" } } } }, "/v1/sequences/{id}": { "get": { "tags": [ "Sequences" ], "summary": "Get a sequence", "description": "Get a sequence with its ordered steps and an enrollment-status breakdown.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Sequence with steps and enrollment stats", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceDetailResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence not found" } } }, "patch": { "tags": [ "Sequences" ], "summary": "Update a sequence", "description": "Update the name, status, and/or exitOnReply flag.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSequenceRequest" } } } }, "responses": { "200": { "description": "Updated sequence", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence not found" } } }, "delete": { "tags": [ "Sequences" ], "summary": "Archive a sequence", "description": "Soft delete — sets the sequence status to ARCHIVED. The record is retained.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Sequence archived", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence not found" } } } }, "/v1/sequences/{id}/steps": { "get": { "tags": [ "Sequences" ], "summary": "List sequence steps", "description": "List all steps for a sequence, ordered by stepOrder ascending.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Ordered list of steps", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceStepListResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence not found" } } }, "post": { "tags": [ "Sequences" ], "summary": "Add a sequence step", "description": "Add a step to a sequence. Appended at the end when stepOrder is omitted.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSequenceStepRequest" } } } }, "responses": { "201": { "description": "Step created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceStepResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence not found" } } } }, "/v1/sequences/{id}/steps/{stepId}": { "patch": { "tags": [ "Sequences" ], "summary": "Update a sequence step", "description": "Update a step's message template, delay, and/or position.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "stepId", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSequenceStepRequest" } } } }, "responses": { "200": { "description": "Updated step", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceStepResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence or step not found" } } }, "delete": { "tags": [ "Sequences" ], "summary": "Delete a sequence step", "description": "Delete a step. Remaining steps are renumbered to close the gap.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "stepId", "in": "path" } ], "responses": { "200": { "description": "Step deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence or step not found" } } } }, "/v1/sequences/{id}/enrollments": { "get": { "tags": [ "Sequences" ], "summary": "List sequence enrollments", "description": "Paginated list of enrollments for a sequence, newest first.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" }, { "schema": { "$ref": "#/components/schemas/EnrollmentStatus" }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "default": 1 }, "required": false, "name": "page", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" } ], "responses": { "200": { "description": "Paginated list of enrollments", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceEnrollmentListResponse" } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence not found" } } }, "post": { "tags": [ "Sequences" ], "summary": "Enroll a contact", "description": "Enroll a contact in the sequence. A contact whose previous enrollment ended (COMPLETED, EXITED, or FAILED) is re-enrolled from step 1.", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EnrollContactRequest" } } } }, "responses": { "201": { "description": "Contact enrolled", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SequenceEnrollmentResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence or contact not found" }, "422": { "description": "SEQUENCE_ARCHIVED (cannot enroll into an archived sequence) or ALREADY_ENROLLED (contact already actively enrolled)" } } } }, "/v1/sequences/{id}/enrollments/{enrollId}": { "delete": { "tags": [ "Sequences" ], "summary": "Exit an enrollment", "description": "Manually exit a contact from the sequence. Sets status to EXITED with reason \"manual\".", "parameters": [ { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "description": "Unique identifier (CUID)", "example": "cmmmdwv6e0002yvot7ph96591" }, "required": true, "name": "enrollId", "in": "path" } ], "responses": { "200": { "description": "Enrollment exited", "content": { "application/json": { "schema": { "type": "object", "properties": { "success": { "type": "boolean", "enum": [ true ] } }, "required": [ "success" ] } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Forbidden – DM Sequences require an Agency plan (PLAN_UPGRADE_REQUIRED)" }, "404": { "description": "Sequence or enrollment not found" } } } }, "/v1/workspaces/{workspaceId}/api-keys": { "get": { "tags": [ "API Keys" ], "summary": "List API keys", "description": "List all active (non-revoked) API keys for a workspace. Includes expiration status indicators.", "parameters": [ { "name": "workspaceId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Workspace ID" } ], "responses": { "200": { "description": "List of API keys with expiration status", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ApiKey" } } }, "required": [ "data" ] } } } }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions (requires OWNER or ADMIN role)" } } }, "post": { "tags": [ "API Keys" ], "summary": "Create API key", "description": "Create a new API key. The full key value is returned **once** in the response — store it securely.", "parameters": [ { "name": "workspaceId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateApiKeyRequest" } } } }, "responses": { "201": { "description": "API key created (full key in response)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateApiKeyResponse" } } } }, "400": { "description": "Validation error" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" } } } }, "/v1/workspaces/{workspaceId}/api-keys/expiring": { "get": { "tags": [ "API Keys" ], "summary": "List expiring API keys", "description": "List API keys expiring within the specified number of days. Useful for dashboards and automated rotation alerts.", "parameters": [ { "name": "workspaceId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "days", "in": "query", "required": false, "schema": { "type": "integer", "minimum": 1, "maximum": 365, "default": 7 }, "description": "Number of days to look ahead for expiring keys (default: 7)" } ], "responses": { "200": { "description": "List of expiring API keys", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExpiringKeysResponse" } } } }, "400": { "description": "Invalid days parameter" }, "401": { "description": "Unauthorized" }, "403": { "description": "Insufficient permissions" } } } }, "/v1/workspaces/{workspaceId}/api-keys/{keyId}": { "patch": { "tags": [ "API Keys" ], "summary": "Update API key", "description": "Update an API key's name, scopes, or IP allowlist.", "parameters": [ { "name": "workspaceId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "keyId", "in": "path", "required": true, "schema": { "type": "string" }, "description": "API key ID" } ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "scopes": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "allowedIps": { "type": "array", "items": { "type": "string" } } } } } } }, "responses": { "200": { "description": "API key updated", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/ApiKey" } }, "required": [ "data" ] } } } }, "400": { "description": "Validation error" }, "404": { "description": "API key not found" } } }, "delete": { "tags": [ "API Keys" ], "summary": "Revoke API key", "description": "Revoke (soft-delete) an API key. The key will immediately stop working.", "parameters": [ { "name": "workspaceId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }, { "name": "keyId", "in": "path", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "API key revoked", "content": { "application/json": { "schema": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } } } }, "404": { "description": "API key not found" } } } }, "/v1/status/platforms/{platform}": { "get": { "tags": [ "Status" ], "summary": "Get specific platform status", "description": "Returns sanitized operational status for a specific platform. No authentication required.", "security": [], "parameters": [ { "name": "platform", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Platform name (e.g., twitter, instagram, linkedin)" } ], "responses": { "200": { "description": "Detailed platform status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PlatformStatusDetailed" } } } }, "404": { "description": "Platform not found" } } } } } }