Zorbit API Docs
API Documentation
Section titled “API Documentation”Base URL
Section titled “Base URL”/api/v1Authentication
Section titled “Authentication”All API endpoints require authentication via Clerk. The user’s session is automatically validated using @clerk/nextjs/server. Include the authentication token in the Authorization header:
Authorization: Bearer <token>Authentication Flow:
- Users authenticate through Clerk
- Clerk provides a session token
- Include the token in all API requests
- The API validates the token and extracts user information
User Management
Section titled “User Management”Get Current User
Section titled “Get Current User”Retrieve the authenticated user’s profile information.
Endpoint: GET /api/v1/user
Headers:
Authorization: Bearer <token>(required)X-Request-ID: <uuid>(optional, for request tracking)
Response Headers:
X-RateLimit-Limit: 1000X-RateLimit-Remaining: 999X-RateLimit-Reset: 1640995200X-Request-ID: <uuid>
Response:
{ "id": "user_xxx", "firstName": "John", "lastName": "Doe", "email": "john.doe@example.com", "bio": "Software Engineer", "imageUrl": "https://...", "imageKey": "user/xxx"}Status Codes:
200- Success401- Unauthorized404- User not found429- Rate limit exceeded500- Internal server error
Update User Profile
Section titled “Update User Profile”Update the authenticated user’s profile information.
Endpoint: PUT /api/v1/user
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(optional, for idempotent requests)
Request Body:
{ "name": "John Doe", "imageKey": "user/xxx"}Response:
{ "id": "user_xxx", "firstName": "John", "lastName": "Doe", "email": "john.doe@example.com", "imageUrl": "https://...", "imageKey": "user/xxx"}Status Codes:
200- Success400- Bad request (validation error)401- Unauthorized409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Post Generation & Management
Section titled “Post Generation & Management”Generate Posts
Section titled “Generate Posts”Generate LinkedIn posts using AI based on a prompt and optional persona.
Endpoint: POST /api/v1/post/generate
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "prompt": "Write a post about AI in healthcare", "personaId": "persona_xxx", "selectedPosts": ["post_id_1", "post_id_2"], "threadId": "thread_xxx", "isFirstMessage": false, "contentLength": "medium"}Response:
{ "posts": [ { "id": "post_xxx", "content": { "text": "Generated post content..." }, "timestamp": "2024-01-01T00:00:00.000Z", "personaId": "persona_xxx", "contentLength": "medium" } ], "partialSuccess": false, "totalRequested": 2, "totalGenerated": 2, "personaUsed": { "id": "persona_xxx", "name": "Tech Professional", "isSystem": false }, "threadId": "thread_xxx", "generationTime": 3.25}Status Codes:
200- Success400- Bad request (missing threadId or invalid parameters)401- Unauthorized402- Payment required (quota exhausted)409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Quota: Consumes post_generation quota (1 unit per post generated)
Rate Limits: 100 requests per hour per user
List Posts
Section titled “List Posts”Retrieve posts with pagination, filtering, and sorting.
Endpoint: GET /api/v1/post
Query Parameters:
page(number, default: 1, min: 1) - Page numberlimit(number, default: 10, min: 1, max: 100) - Items per pagetype(string, optional) - Filter by post typepersonaId(string, optional) - Filter by persona IDscheduledOnly(boolean, optional) - Only return scheduled postspostedOnly(boolean, optional) - Only return posted contentsort(string, default: “createdAt:desc”) - Sort format: “field:direction”- Fields:
createdAt,scheduledOn,linkedinPostedAt - Directions:
asc,desc
- Fields:
Response:
{ "posts": [ { "id": "post_xxx", "content": "Post content...", "type": "post", "personaId": "persona_xxx", "createdAt": "2024-01-01T00:00:00.000Z", "scheduledOn": null, "isPostedOnLinkedin": false, "linkedinUrl": null } ], "hasMore": true, "totalCount": 50, "page": 1, "totalPages": 5}Status Codes:
200- Success400- Bad request (invalid query parameters)401- Unauthorized429- Rate limit exceeded500- Internal server error
Rate Limits: 1000 requests per hour per user
Create Post
Section titled “Create Post”Create a new post manually.
Endpoint: POST /api/v1/post
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "content": "Post content here", "type": "post", "personaId": "persona_xxx", "isSaved": false, "image": "data:image/png;base64,..."}Response:
{ "id": "post_xxx", "content": "Post content here", "type": "post", "userId": "user_xxx", "createdAt": "2024-01-01T00:00:00.000Z"}Status Codes:
201- Created400- Bad request (missing content or validation error)401- Unauthorized409- Conflict (idempotency key already used)413- Payload too large (image size limit exceeded)429- Rate limit exceeded500- Internal server error
Rate Limits: 500 requests per hour per user
Get Post
Section titled “Get Post”Retrieve a specific post by ID.
Endpoint: GET /api/v1/post/[id]
Response:
{ "id": "post_xxx", "title": "Post Title", "content": "Post content", "imageUrl": "https://...", "imageKey": "post/xxx", "published": false, "isPostedOnLinkedin": false, "linkedinUrl": null, "linkedinPostedAt": null, "type": "post", "source": "manual", "createdAt": "2024-01-01T00:00:00.000Z", "updatedAt": "2024-01-01T00:00:00.000Z", "isLiked": false, "isDisliked": false, "isSaved": false, "userId": "user_xxx", "personaId": "persona_xxx"}Status Codes:
200- Success401- Unauthorized403- Forbidden (not post owner)404- Post not found429- Rate limit exceeded500- Internal server error
Update Post
Section titled “Update Post”Update an existing post.
Endpoint: PUT /api/v1/post/[id]
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "content": "Updated content", "type": "post", "isLiked": true, "isDisliked": false, "isSaved": true, "scheduledOn": "2024-12-31T12:00:00.000Z", "image": "data:image/png;base64,..."}Response:
{ "id": "post_xxx", "content": "Updated content", "updatedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success400- Bad request (no valid fields to update or validation error)401- Unauthorized403- Forbidden (not post owner)404- Post not found409- Conflict (idempotency key already used)413- Payload too large (image size limit exceeded)429- Rate limit exceeded500- Internal server error
Delete Post
Section titled “Delete Post”Soft delete a post.
Endpoint: DELETE /api/v1/post/[id]
Headers:
Authorization: Bearer <token>(required)Idempotency-Key: <uuid>(recommended)
Response:
{ "success": true, "deletedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success401- Unauthorized403- Forbidden (not post owner)404- Post not found409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Persona Management
Section titled “Persona Management”List Personas
Section titled “List Personas”Get all personas for the authenticated user.
Endpoint: GET /api/v1/persona
Response:
[ { "id": "persona_xxx", "name": "Tech Professional", "description": "A tech-savvy professional persona", "targetAudience": "Tech professionals", "profession": "Software Engineer", "relevantKeywords": "AI, ML, Tech", "opinions": "Innovation-focused", "vocabulary": "Technical terms", "avoidWords": "Jargon", "endGoal": "Engage tech community", "customHashtag": "#TechLife", "fixCta": "Call to action", "createdAt": "2024-01-01T00:00:00.000Z", "updatedAt": "2024-01-01T00:00:00.000Z" }]Status Codes:
200- Success401- Unauthorized429- Rate limit exceeded500- Internal server error
Create Persona
Section titled “Create Persona”Create a new persona manually.
Endpoint: POST /api/v1/persona
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "name": "Tech Professional", "description": "A tech-savvy professional persona", "defaultPrompt": "Default prompt", "targetAudience": "Tech professionals", "profession": "Software Engineer", "relevantKeywords": "AI, ML, Tech", "opinions": "Innovation-focused", "vocabulary": "Technical terms", "avoidWords": "Jargon", "endGoal": "Engage tech community", "customHashtag": "#TechLife", "fixCta": "Call to action"}Response:
{ "id": "persona_xxx", "name": "Tech Professional", "createdAt": "2024-01-01T00:00:00.000Z"}Status Codes:
201- Created400- Bad request (missing name or validation error)401- Unauthorized402- Payment required (quota exhausted)409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Quota: Consumes personas quota (1 unit)
Rate Limits: 50 requests per hour per user
Generate Persona
Section titled “Generate Persona”Generate a persona using AI based on a description.
Endpoint: POST /api/v1/persona/generate
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "prompt": "Create a persona for a healthcare professional who focuses on patient care and medical innovation"}Response:
{ "id": "persona_xxx", "name": "Healthcare Professional", "description": "A healthcare professional focused on patient care...", "targetAudience": "Healthcare professionals and patients", "profession": "Medical Professional", "relevantKeywords": "Healthcare, Medicine, Patient Care", "opinions": "Patient-first approach", "vocabulary": "Medical terminology", "avoidWords": "Overly technical jargon", "endGoal": "Educate and engage healthcare community", "createdAt": "2024-01-01T00:00:00.000Z"}Status Codes:
201- Created400- Bad request (invalid prompt or validation error)401- Unauthorized402- Payment required (quota exhausted)409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Quota: Consumes personas quota (1 unit)
Rate Limits: 20 requests per hour per user
Get Persona
Section titled “Get Persona”Retrieve a specific persona by ID.
Endpoint: GET /api/v1/persona/[id]
Response:
{ "id": "persona_xxx", "name": "Tech Professional", "description": "...", "createdAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success401- Unauthorized403- Forbidden (not persona owner)404- Persona not found429- Rate limit exceeded500- Internal server error
Update Persona
Section titled “Update Persona”Update an existing persona.
Endpoint: PUT /api/v1/persona/[id]
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "name": "Updated Name", "description": "Updated description", "targetAudience": "Updated audience"}Response:
{ "id": "persona_xxx", "name": "Updated Name", "updatedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success400- Bad request (validation error)401- Unauthorized403- Forbidden (not persona owner)404- Persona not found409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Delete Persona
Section titled “Delete Persona”Soft delete a persona.
Endpoint: DELETE /api/v1/persona/[id]
Headers:
Authorization: Bearer <token>(required)Idempotency-Key: <uuid>(recommended)
Response:
{ "success": true, "deletedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success401- Unauthorized403- Forbidden (not persona owner)404- Persona not found409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Note: Deletion decreases the persona usage count by 1.
Get Persona Dropdown
Section titled “Get Persona Dropdown”Get personas in a simplified format for dropdowns.
Endpoint: GET /api/v1/persona/dropdown
Response:
[ { "id": "persona_xxx", "name": "Tech Professional" }]Status Codes:
200- Success401- Unauthorized429- Rate limit exceeded500- Internal server error
Comment Generation
Section titled “Comment Generation”Generate Comment
Section titled “Generate Comment”Generate a single comment for a LinkedIn post.
Endpoint: POST /api/v1/comments/generate
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "postContent": "Original LinkedIn post content...", "tone": "friendly", "length": "short", "platform": "linkedin", "userComment": "Custom instruction or draft", "authorName": "Jane Smith", "authorUrl": "https://linkedin.com/in/janesmith", "authorBio": "Product Manager at Tech Solutions Inc."}Response (LinkedIn):
{ "comment": { "quote": "Great insights! This really resonates with my experience...", "profileUrl": "https://linkedin.com/in/janesmith" }, "message": "Comment generated and saved", "generationTime": 2.5, "platform": "linkedin"}Response (X/Twitter):
{ "comment": "Great insights! This really resonates...", "message": "Reply generated", "generationTime": 2.3, "platform": "x"}Status Codes:
200- Success400- Bad request (missing postContent, invalid platform, or validation error)401- Unauthorized402- Payment required (quota exhausted)409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Quota: Consumes comment_generation quota (1 unit)
Rate Limits: 200 requests per hour per user
Beast Mode Comments
Section titled “Beast Mode Comments”Generate 5 diverse comment variations in a single request.
Endpoint: POST /api/v1/comments/beast-mode
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "postContent": "Original LinkedIn post content...", "platform": "linkedin", "userComment": "Custom instruction", "authorName": "Jane Smith", "authorBio": "Product Manager"}Response:
{ "comments": [ { "quote": "Launch day! 🎉", "type": "short" }, { "quote": "6 months well spent! Can't wait to try it out.", "type": "short" }, { "quote": "That feeling when you finally ship... both exciting and nerve-wracking! Congrats on the launch.", "type": "medium" }, { "quote": "Been there with product launches. The real work starts now with customer feedback!", "type": "short" }, { "quote": "Love how you focused on customer pain points rather than just features. What was the biggest challenge during development?", "type": "medium" } ], "message": "Beast mode comments generated", "generationTime": 3.25, "platform": "linkedin"}Status Codes:
200- Success400- Bad request (missing postContent, invalid platform, or validation error)401- Unauthorized402- Payment required (quota exhausted, requires 5 units)409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Quota: Consumes comment_generation quota (5 units)
Rate Limits: 40 requests per hour per user
List Comments
Section titled “List Comments”Get all comments with pagination and search.
Endpoint: GET /api/v1/comments
Query Parameters:
page(number, default: 1, min: 1) - Page numberlimit(number, default: 10, min: 1, max: 100) - Items per pagesearch(string, optional, max: 100 chars) - Search by first or last name
Response:
{ "comments": [ { "id": "comment_xxx", "firstName": "John", "lastName": "Doe", "title": "Software Engineer", "quote": "Great post!", "date": "2024-01-01T00:00:00.000Z" } ], "pagination": { "total": 50, "page": 1, "limit": 10, "totalPages": 5 }}Status Codes:
200- Success400- Bad request (invalid query parameters)401- Unauthorized429- Rate limit exceeded500- Internal server error
Rate Limits: 1000 requests per hour per user
Create Comment
Section titled “Create Comment”Create a comment manually.
Endpoint: POST /api/v1/comments
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "firstName": "John", "lastName": "Doe", "title": "Software Engineer", "quote": "Great post!", "image": ""}Response:
{ "id": "comment_xxx", "firstName": "John", "lastName": "Doe", "quote": "Great post!", "createdAt": "2024-01-01T00:00:00.000Z"}Status Codes:
201- Created400- Bad request (missing required fields or validation error)401- Unauthorized409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Delete Comment
Section titled “Delete Comment”Delete a comment.
Endpoint: DELETE /api/v1/comments/[id]
Headers:
Authorization: Bearer <token>(required)Idempotency-Key: <uuid>(recommended)
Response:
{ "success": true, "deletedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success401- Unauthorized403- Forbidden (not comment owner)404- Comment not found409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Content Ideas
Section titled “Content Ideas”Generate Content Ideas
Section titled “Generate Content Ideas”Generate content ideas using AI based on a prompt.
Endpoint: POST /api/v1/idea
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "prompt": "Ideas for tech industry content", "threadId": "thread_xxx"}Response:
{ "thread": { "id": "thread_xxx", "title": "Ideas for tech industry content", "type": "idea", "createdAt": "2024-01-01T00:00:00.000Z" }, "promptMessage": { "id": "message_xxx", "content": "Ideas for tech industry content", "createdAt": "2024-01-01T00:00:00.000Z" }, "responseMessage": { "id": "message_xxx", "content": "Generated ideas for: Ideas for tech industry content", "contentIdeas": [ { "id": "idea_xxx", "title": "The Future of AI in Healthcare", "content": "Detailed content description...", "keyTakeaways": ["Takeaway 1", "Takeaway 2"], "controversialAngle": "Controversial perspective..." } ], "createdAt": "2024-01-01T00:00:00.000Z" }}Status Codes:
200- Success400- Bad request (missing prompt or validation error)401- Unauthorized402- Payment required (quota exhausted)404- Thread not found (if threadId provided)409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Quota: Consumes idea_generation quota (1 unit per idea generated)
Rate Limits: 50 requests per hour per user
Get Content Ideas
Section titled “Get Content Ideas”Retrieve content ideas by thread or message.
Endpoint: GET /api/v1/idea
Query Parameters:
threadId(string, optional) - Get all ideas for a threadmessageId(string, optional) - Get ideas for a specific message
Response:
[ { "id": "idea_xxx", "title": "The Future of AI in Healthcare", "content": "Detailed content description...", "keyTakeaways": ["Takeaway 1", "Takeaway 2"], "controversialAngle": "Controversial perspective...", "createdAt": "2024-01-01T00:00:00.000Z" }]Status Codes:
200- Success400- Bad request (invalid query parameters)401- Unauthorized429- Rate limit exceeded500- Internal server error
Get Content Idea
Section titled “Get Content Idea”Retrieve a specific content idea by ID.
Endpoint: GET /api/v1/idea/[id]
Response:
{ "id": "idea_xxx", "title": "The Future of AI in Healthcare", "content": "Detailed content description...", "keyTakeaways": ["Takeaway 1", "Takeaway 2"], "controversialAngle": "Controversial perspective..."}Status Codes:
200- Success401- Unauthorized403- Forbidden (not idea owner)404- Idea not found429- Rate limit exceeded500- Internal server error
Feed Generation
Section titled “Feed Generation”Generate Feed Posts
Section titled “Generate Feed Posts”Generate dynamic feed posts based on user context (ideas, personas, liked/saved posts).
Endpoint: GET /api/v1/feed
Query Parameters:
limit(number, default: 5, min: 1, max: 5) - Number of posts to generatecursor(string, optional) - Pagination cursor
Response:
{ "posts": [ { "id": "post_xxx", "content": { "text": "Generated feed post content..." }, "timestamp": "2024-01-01T00:00:00.000Z", "isLiked": false, "isDisliked": false, "isSaved": false, "metadata": { "sourceType": "idea", "sourceId": "idea_xxx", "contentLength": "medium", "generatedWithWebSearch": false } } ], "nextCursor": "post_xxx", "hasMore": true}Status Codes:
200- Success400- Bad request (invalid query parameters)401- Unauthorized402- Payment required (quota exhausted)429- Rate limit exceeded500- Internal server error
Quota: Consumes post_generation quota (1 unit per post generated)
Rate Limits: 100 requests per hour per user
Note: The API uses user’s saved ideas, personas, liked posts, and saved posts as context for generation. May use web search (30% probability) for more relevant content.
Get Feed History
Section titled “Get Feed History”Retrieve feed generation history.
Endpoint: GET /api/v1/feed/history
Query Parameters:
page(number, default: 1) - Page numberlimit(number, default: 10, max: 100) - Items per page
Response:
[ { "id": "post_xxx", "content": "Feed post content", "createdAt": "2024-01-01T00:00:00.000Z", "source": "feed" }]Status Codes:
200- Success400- Bad request (invalid query parameters)401- Unauthorized429- Rate limit exceeded500- Internal server error
Image Generation
Section titled “Image Generation”Generate Image
Section titled “Generate Image”Generate an image for a LinkedIn post using AI.
Endpoint: POST /api/v1/generate-image-replicate
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "postContent": "LinkedIn post content...", "postId": "post_xxx", "customPrompt": "A professional image of..."}Response:
{ "success": true, "imageUrl": "https://...", "imageKey": "post/xxx"}Status Codes:
200- Success400- Bad request (missing postContent or validation error)401- Unauthorized402- Payment required (quota exhausted)409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Quota: Consumes image_creation quota (1 unit)
Rate Limits: 30 requests per hour per user
Note: If postId is provided, the image is automatically attached to the post. The API generates an image prompt from post content if customPrompt is not provided.
Download Image
Section titled “Download Image”Download an image by key.
Endpoint: GET /api/v1/download-image
Query Parameters:
key(string, required) - Image key
Response: Image file (binary) with appropriate Content-Type header
Status Codes:
200- Success400- Bad request (missing key)401- Unauthorized403- Forbidden (not image owner)404- Image not found429- Rate limit exceeded500- Internal server error
Rate Limits: 1000 requests per hour per user
Refresh Image URL
Section titled “Refresh Image URL”Refresh a signed image URL.
Endpoint: POST /api/v1/refresh-image-url
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)
Request Body:
{ "imageKey": "post/xxx"}Response:
{ "imageUrl": "https://...", "expiresAt": "2024-01-01T01:00:00.000Z"}Status Codes:
200- Success400- Bad request (missing imageKey or validation error)401- Unauthorized403- Forbidden (not image owner)404- Image not found429- Rate limit exceeded500- Internal server error
Subscriptions & Plans
Section titled “Subscriptions & Plans”Get Subscription
Section titled “Get Subscription”Get the current user’s subscription.
Endpoint: GET /api/v1/subscriptions
Response:
{ "id": "sub_xxx", "userId": "user_xxx", "planId": "plan_xxx", "status": "active", "currentPeriodStart": "2024-01-01T00:00:00.000Z", "currentPeriodEnd": "2024-12-31T23:59:59.000Z", "cancelAtPeriodEnd": false}Status Codes:
200- Success (returns null if no subscription)401- Unauthorized429- Rate limit exceeded500- Internal server error
Cancel Subscription
Section titled “Cancel Subscription”Cancel the current user’s subscription.
Endpoint: POST /api/v1/subscriptions/cancel
Headers:
Authorization: Bearer <token>(required)Idempotency-Key: <uuid>(recommended)
Response:
{ "success": true, "message": "Subscription will be cancelled at the end of the current period", "cancelAt": "2024-12-31T23:59:59.000Z"}Status Codes:
200- Success401- Unauthorized404- No active subscription409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Renew Free Subscription
Section titled “Renew Free Subscription”Renew a free subscription.
Endpoint: POST /api/v1/subscriptions/renew-free
Headers:
Authorization: Bearer <token>(required)Idempotency-Key: <uuid>(recommended)
Response:
{ "success": true, "subscription": { "id": "sub_xxx", "status": "active", "currentPeriodEnd": "2024-12-31T23:59:59.000Z" }}Status Codes:
200- Success400- Bad request (not eligible for free renewal)401- Unauthorized409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Get Plans
Section titled “Get Plans”Get all active subscription plans.
Endpoint: GET /api/v1/plans
Response:
[ { "id": "plan_xxx", "name": "Pro Plan", "description": "Professional features", "price": 29.99, "currency": "USD", "interval": "month", "features": ["Feature 1", "Feature 2"], "postGenerationLimit": 100, "ideaGenerationLimit": 50, "personaLimit": 10, "imageCreationLimit": 20, "isActive": true }]Status Codes:
200- Success401- Unauthorized429- Rate limit exceeded500- Internal server error
Get Plan
Section titled “Get Plan”Get a specific plan by ID.
Endpoint: GET /api/v1/plans/[id]
Response:
{ "id": "plan_xxx", "name": "Pro Plan", "price": 29.99, "features": ["Feature 1", "Feature 2"]}Status Codes:
200- Success404- Plan not found429- Rate limit exceeded500- Internal server error
Create Plan (Admin Only)
Section titled “Create Plan (Admin Only)”Create a new subscription plan.
Endpoint: POST /api/v1/plans
Headers:
Authorization: Bearer <token>(required, admin role)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "name": "Pro Plan", "description": "Professional features", "price": 29.99, "currency": "USD", "interval": "month", "features": ["Feature 1", "Feature 2"], "postGenerationLimit": 100, "ideaGenerationLimit": 50, "personaLimit": 10, "imageCreationLimit": 20}Response:
{ "id": "plan_xxx", "name": "Pro Plan", "createdAt": "2024-01-01T00:00:00.000Z"}Status Codes:
201- Created400- Bad request (missing required fields or validation error)401- Unauthorized403- Forbidden (admin role required)409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Usage & Quotas
Section titled “Usage & Quotas”Get Usage Quotas
Section titled “Get Usage Quotas”Get all usage quotas for the current user.
Endpoint: GET /api/v1/usage/quotas
Response:
{ "post_generation": { "limit": 100, "used": 45, "remaining": 55, "resetAt": "2024-02-01T00:00:00.000Z" }, "idea_generation": { "limit": 50, "used": 20, "remaining": 30, "resetAt": "2024-02-01T00:00:00.000Z" }, "personas": { "limit": 10, "used": 3, "remaining": 7, "resetAt": null }, "comment_generation": { "limit": 200, "used": 150, "remaining": 50, "resetAt": "2024-02-01T00:00:00.000Z" }, "image_creation": { "limit": 20, "used": 5, "remaining": 15, "resetAt": "2024-02-01T00:00:00.000Z" }}Status Codes:
200- Success401- Unauthorized429- Rate limit exceeded500- Internal server error
Check Quota
Section titled “Check Quota”Check if a specific quota is available.
Endpoint: GET /api/v1/quotas/check
Query Parameters:
type(string, required) - Quota type:post_generation,idea_generation,personas,comment_generation,image_creation
Response (Available):
{ "available": true, "quotaType": "post_generation", "remaining": 55, "limit": 100}Response (Exhausted):
{ "available": false, "error": "Quota exhausted", "quotaType": "post_generation", "upgradeRequired": true, "remaining": 0, "limit": 100, "resetAt": "2024-02-01T00:00:00.000Z"}Status Codes:
200- Available400- Bad request (missing type or invalid type)401- Unauthorized402- Payment required (quota exhausted)429- Rate limit exceeded500- Internal server error
Saved Items
Section titled “Saved Items”Get Saved Items
Section titled “Get Saved Items”Get all saved posts and content ideas.
Endpoint: GET /api/v1/saved
Query Parameters:
type(string, optional) - Filter by type:"post"|"idea"(null for all)cursor(string, optional) - Pagination cursorlimit(number, default: 10, min: 1, max: 100) - Items per page
Response:
{ "posts": [ { "id": "post_xxx", "content": { "text": "Post content", "image": "https://...", "imageKey": "post/xxx" }, "timestamp": "2024-01-01T00:00:00.000Z", "isSaved": true, "isLiked": false, "isDisliked": false, "isPostedOnLinkedin": false, "linkedinUrl": null, "linkedinPostedAt": null, "scheduledOn": null } ], "ideas": [ { "id": "idea_xxx", "title": "Content Idea", "content": "Idea content...", "keyTakeaways": ["Takeaway 1"], "controversialAngle": "Angle..." } ], "nextCursor": "post_xxx", "hasMore": true}Status Codes:
200- Success400- Bad request (invalid query parameters)401- Unauthorized404- User not found429- Rate limit exceeded500- Internal server error
LinkedIn Integration
Section titled “LinkedIn Integration”Share Post to LinkedIn
Section titled “Share Post to LinkedIn”Share a post directly to LinkedIn.
Endpoint: POST /api/v1/post/share-linkedin
Headers:
Authorization: Bearer <token>(required)Content-Type: application/json(required)Idempotency-Key: <uuid>(recommended)
Request Body:
{ "postId": "post_xxx"}Response:
{ "success": true, "shareUrl": "https://www.linkedin.com/feed/update/xxx", "sharedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success400- Bad request (missing postId or validation error)401- Unauthorized403- Forbidden (missing LinkedIn permission or not post owner)404- Post not found409- Conflict (idempotency key already used)429- Rate limit exceeded500- Internal server error
Note: Requires LinkedIn OAuth with w_member_social scope.
Rate Limits: 50 requests per hour per user
Publish Scheduled Posts
Section titled “Publish Scheduled Posts”Publish scheduled posts (internal/cron endpoint).
Endpoint: POST /api/v1/post/publish
Headers:
Authorization: Bearer <api-key>(required, internal API key)Content-Type: application/json(required)X-API-Key: <key>(required, alternative to Authorization header)
Request Body:
{ "apiKey": "xxx"}Response:
{ "success": true, "totalProcessed": 5, "successCount": 4, "failureCount": 1, "results": [ { "postId": "post_xxx", "success": true, "shareUrl": "https://www.linkedin.com/feed/update/xxx" } ], "processedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success400- Bad request (invalid format)401- Unauthorized (invalid API key)429- Rate limit exceeded500- Internal server error
Note: This endpoint is designed for cron jobs or external services. It processes posts scheduled within the next 2 minutes or past scheduled posts that haven’t been posted yet.
Webhooks
Section titled “Webhooks”Clerk Webhook
Section titled “Clerk Webhook”Handle Clerk user synchronization events.
Endpoint: POST /api/v1/webhook/clerk
Headers:
svix-id: <id>(required, webhook ID)svix-timestamp: <timestamp>(required, webhook timestamp)svix-signature: <signature>(required, webhook signature)
Request: Clerk webhook payload (verified via signature)
Response:
{ "success": true, "processedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success400- Bad request (invalid payload)401- Unauthorized (invalid webhook signature)500- Internal server error
Note: Used to sync user data (firstname, email, lastname, photo) from Clerk to the database. All webhook requests are verified using signature validation.
DodoPayments Webhook
Section titled “DodoPayments Webhook”Handle payment and subscription events from DodoPayments.
Endpoint: POST /api/v1/webhook/dodopayments
Headers:
X-Webhook-Signature: <signature>(required, webhook signature)X-Webhook-Timestamp: <timestamp>(required, webhook timestamp)
Request: DodoPayments webhook payload (verified via signature)
Response:
{ "success": true, "processedAt": "2024-01-01T00:00:00.000Z"}Status Codes:
200- Success400- Bad request (invalid payload)401- Unauthorized (invalid webhook signature)500- Internal server error
Note: Handles subscription creation, updates, cancellations, and payment events. All webhook requests are verified using signature validation.
Error Responses
Section titled “Error Responses”All error responses follow a consistent format:
{ "error": { "code": "ERROR_CODE", "message": "Human-readable error message", "details": "Additional error details", "requestId": "req_xxx", "timestamp": "2024-01-01T00:00:00.000Z" }, "quota": { "type": "post_generation", "limit": 100, "used": 100, "remaining": 0, "resetAt": "2024-02-01T00:00:00.000Z" }}Common Status Codes
Section titled “Common Status Codes”200- Success201- Created400- Bad Request (invalid parameters, validation errors)401- Unauthorized (authentication required or invalid token)402- Payment Required (quota exhausted)403- Forbidden (insufficient permissions)404- Not Found409- Conflict (idempotency key already used, resource conflict)413- Payload Too Large (request body exceeds size limit)429- Too Many Requests (rate limit exceeded)500- Internal Server Error503- Service Unavailable (temporary service outage)
Rate Limiting
Section titled “Rate Limiting”All API responses include rate limiting headers:
X-RateLimit-Limit: Maximum requests per periodX-RateLimit-Remaining: Remaining requests in current periodX-RateLimit-Reset: Unix timestamp when the rate limit resets
When rate limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header indicating seconds to wait before retrying.
Rate limits are applied per user and vary by endpoint:
- Read operations: 1000 requests/hour
- Write operations: 500 requests/hour
- AI generation: 20-200 requests/hour (varies by endpoint)
- Webhooks: No rate limiting (signature verification required)
Pagination
Section titled “Pagination”Cursor-based Pagination
Section titled “Cursor-based Pagination”Used for endpoints that return large datasets with consistent ordering:
- Use
cursorquery parameter for pagination - Response includes
nextCursorandhasMorefields - Cursor is an opaque string that should be passed as-is
- When
hasMoreisfalse, no more results are available
Offset-based Pagination
Section titled “Offset-based Pagination”Used for endpoints that support flexible sorting:
- Use
pageandlimitquery parameters - Response includes
totalCount,totalPages, andhasMorefields pagestarts at 1limithas a maximum value (typically 100)
Request Validation
Section titled “Request Validation”All request bodies and query parameters are validated according to OpenAPI schemas. Validation errors return 400 Bad Request with detailed error messages indicating which fields failed validation.
Validation Rules:
- Required fields must be present
- String fields have maximum length limits
- Numeric fields have min/max value constraints
- Enum fields must match allowed values
- Date fields must be valid ISO 8601 format
- Email fields must be valid email format
- URL fields must be valid URLs
Idempotency
Section titled “Idempotency”For state-changing operations (POST, PUT, DELETE), include an Idempotency-Key header with a unique UUID. This ensures that if a request is retried due to network issues, the operation is not performed multiple times.
Idempotency Behavior:
- First request with a key: Operation is performed, response is cached
- Subsequent requests with the same key: Returns cached response with
409 Conflictstatus - Idempotency keys are valid for 24 hours
- Keys are scoped per user and endpoint
The API supports Cross-Origin Resource Sharing (CORS) for authorized domains. CORS headers are automatically included in responses:
Access-Control-Allow-Origin: Allowed originAccess-Control-Allow-Methods: Allowed HTTP methodsAccess-Control-Allow-Headers: Allowed request headersAccess-Control-Max-Age: Cache duration for preflight requests
OpenAPI Specification
Section titled “OpenAPI Specification”A complete OpenAPI 3.0 specification is available at /api/v1/openapi.json and /api/v1/openapi.yaml. This specification includes:
- All endpoints with request/response schemas
- Authentication requirements
- Rate limiting information
- Error response formats
- Example requests and responses
Interactive API documentation is available at /api/v1/docs (Swagger UI).
Webhook Signature Verification
Section titled “Webhook Signature Verification”All webhook endpoints require signature verification to ensure requests are authentic:
-
Clerk Webhooks: Use Svix signature verification
- Verify
svix-signatureheader - Check
svix-timestampfor replay attacks - Validate payload against signature
- Verify
-
DodoPayments Webhooks: Use HMAC signature verification
- Verify
X-Webhook-Signatureheader - Check
X-Webhook-Timestampfor replay attacks - Validate payload against secret key
- Verify
Webhook signatures must be verified within 5 minutes of the timestamp to prevent replay attacks.
Logging and Monitoring
Section titled “Logging and Monitoring”All API requests are logged with:
- Request ID (from
X-Request-IDheader or generated) - User ID
- Endpoint and method
- Request timestamp
- Response status code
- Processing time
- Error details (if applicable)
Performance metrics are tracked including:
- Request latency (p50, p95, p99)
- Error rates by endpoint
- Quota usage patterns
- Rate limit violations
Data Formats
Section titled “Data Formats”- Timestamps: All timestamps are in ISO 8601 format (UTC):
2024-01-01T00:00:00.000Z - Image Uploads: Accept base64-encoded data URIs with format:
data:image/<type>;base64,<data> - Maximum Image Size: 10MB per image
- Maximum Request Body Size: 5MB
- Content-Type: All requests must include
Content-Type: application/jsonheader for JSON payloads
Soft Deletes
Section titled “Soft Deletes”All delete operations perform soft deletes:
- Records are marked as deleted with
isDeleted: trueflag - Deleted records are not returned in list queries
- Deleted records can be restored within 30 days
- Permanent deletion occurs after 30 days
System Personas
Section titled “System Personas”System personas are pre-configured personas available to all users:
- System personas are not stored in user databases
- System personas can be used in post generation
- System personas have example posts and knowledge stacks
- System personas are identified by special IDs
Thread-based Conversations
Section titled “Thread-based Conversations”Post and idea generation support thread-based conversations:
- Threads group related messages together
- Threads maintain conversation context
- Previous messages in a thread inform AI generation
- Threads can be created automatically or explicitly
- Thread history is limited to last 10 messages for context
Changelog
Section titled “Changelog”API changes are documented and versioned. Breaking changes result in a new API version. Non-breaking changes are added to the current version.
Current Version: v1
Deprecation Policy:
- Deprecated endpoints are marked in documentation
- Deprecated endpoints remain functional for 6 months
- Clients receive deprecation warnings in response headers
- Breaking changes require a new API version