{
  "openapi": "3.1.0",
  "info": {
    "title": "RecurPost Public API",
    "version": "1.0.0",
    "summary": "Schedule and publish social media posts, manage content libraries, and generate AI content on RecurPost.",
    "description": "The RecurPost Public API lets you post to connected social accounts (Facebook, Instagram, X/Twitter, LinkedIn, TikTok, Pinterest, Google Business Profile, YouTube, Threads, Bluesky), add evergreen content to recurring libraries, pull posting history, and generate post copy or images with AI. All endpoints are POST and accept application/json or application/x-www-form-urlencoded bodies. Authentication is per-request via the emailid and pass_key body fields; generate your API Password Key from Account Settings in the RecurPost dashboard (it is NOT your login password). An MCP server (npm: recurpost-mcp) and an n8n community node (npm: n8n-nodes-recurpost) wrap this API for AI assistants and workflow tools.",
    "termsOfService": "https://recurpost.com/terms-and-conditions-of-use/",
    "contact": {
      "name": "RecurPost Support",
      "url": "https://recurpost.com/support/",
      "email": "support@recurpost.com"
    }
  },
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://developers.recurpost.com/"
  },
  "servers": [
    { "url": "https://social.recurpost.com" }
  ],
  "paths": {
    "/api/user_login": {
      "post": {
        "operationId": "userLogin",
        "summary": "Verify API credentials",
        "description": "Verify your emailid and pass_key are valid. Use this to test authentication before calling other endpoints.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/AuthOnly" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/AuthOnly" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/api/connect_social_account_urls": {
      "post": {
        "operationId": "connectSocialAccountUrls",
        "summary": "Get URLs to connect new social accounts",
        "description": "Returns per-platform OAuth URLs a user can open in a browser to connect new social media accounts to their RecurPost account.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/AuthOnly" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/AuthOnly" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/api/social_account_list": {
      "post": {
        "operationId": "socialAccountList",
        "summary": "List connected social accounts",
        "description": "Returns all social media accounts connected to the RecurPost account, including the account IDs required by /api/post_content and /api/history_data.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/AuthOnly" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/AuthOnly" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/api/library_list": {
      "post": {
        "operationId": "libraryList",
        "summary": "List content libraries",
        "description": "Returns all recurring-content libraries in the account, including the library IDs required by /api/add_content_in_library.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/AuthOnly" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/AuthOnly" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/api/history_data": {
      "post": {
        "operationId": "historyData",
        "summary": "Get posting history for a social account",
        "description": "Returns up to 100 posts per request for one social account, with a total_posts count for the date range. Without start_date/end_date it returns the last 30 minutes on the first call and everything since the last fetch on subsequent calls.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/HistoryRequest" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/HistoryRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "Posting history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total_posts": { "type": "integer", "description": "Total posts matching the date range" },
                    "data": { "type": "array", "description": "Post history records (max 100 per request)", "items": { "type": "object" } }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/api/add_content_in_library": {
      "post": {
        "operationId": "addContentInLibrary",
        "summary": "Add a post to a recurring content library",
        "description": "Adds content to a library for evergreen recurring posting; RecurPost publishes it automatically per the library's schedule. Supports per-platform message overrides, media, first comments, and platform-specific options.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/AddLibraryContentRequest" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/AddLibraryContentRequest" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/api/post_content": {
      "post": {
        "operationId": "postContent",
        "summary": "Publish or schedule a one-off post",
        "description": "Publishes a post to a social account immediately, or at schedule_date_time if provided (must be in the future, else error 415). Supports per-platform message overrides, media, first comments, and platform-specific options.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/PostContentRequest" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/PostContentRequest" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" },
          "415": { "description": "Schedule time error: invalid or past datetime for the scheduled post" }
        }
      }
    },
    "/api/generate_content_with_ai": {
      "post": {
        "operationId": "generateContentWithAi",
        "summary": "Generate post copy with AI",
        "description": "Generates social media post text from a prompt. Supports multi-turn refinement: pass back ai_id and chat_progress from the previous response to continue the conversation.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/GenerateContentRequest" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/GenerateContentRequest" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/Success" },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    },
    "/api/generate_image_with_ai": {
      "post": {
        "operationId": "generateImageWithAi",
        "summary": "Generate an image with AI",
        "description": "Generates an image from a text prompt. The response's image_url field contains the generated image URL, usable in image_url arrays for posting endpoints.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/GenerateImageRequest" } },
            "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/GenerateImageRequest" } }
          }
        },
        "responses": {
          "200": {
            "description": "Generated image",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "image_url": { "type": "string", "format": "uri", "description": "URL of the generated image" } }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/AuthError" }
        }
      }
    }
  },
  "components": {
    "responses": {
      "Success": {
        "description": "Request completed successfully",
        "content": { "application/json": { "schema": { "type": "object" } } }
      },
      "ValidationError": { "description": "Missing or invalid parameters" },
      "AuthError": { "description": "Invalid emailid or pass_key" }
    },
    "schemas": {
      "AuthOnly": {
        "type": "object",
        "required": ["emailid", "pass_key"],
        "properties": {
          "emailid": { "type": "string", "format": "email", "description": "RecurPost account email address" },
          "pass_key": { "type": "string", "description": "API Password Key from Account Settings (NOT the login password)" }
        }
      },
      "HistoryRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/AuthOnly" },
          {
            "type": "object",
            "required": ["id"],
            "properties": {
              "id": { "type": "string", "description": "Social account ID from /api/social_account_list" },
              "start_date": { "type": "string", "description": "Start of date range, format Y-m-d H:i:s (e.g. 2026-03-01 00:00:00). Default: last 30 minutes, or last fetched time on subsequent requests." },
              "end_date": { "type": "string", "description": "End of date range, format Y-m-d H:i:s. Default: current time." },
              "is_get_video_updates": { "type": "boolean", "description": "Include video posts in the response", "default": true }
            }
          }
        ]
      },
      "MediaFields": {
        "type": "object",
        "properties": {
          "image_url": { "type": "array", "items": { "type": "string", "format": "uri" }, "description": "Array of publicly accessible image URLs. Must be an array, not a string." },
          "video_url": { "type": "string", "format": "uri", "description": "Publicly accessible video URL" },
          "url": { "type": "string", "format": "uri", "description": "Website URL to share with the post" },
          "host_images_on_recurpost": { "type": "boolean", "description": "Copy images to RecurPost servers for reliability", "default": true }
        }
      },
      "PlatformMessageFields": {
        "type": "object",
        "description": "Per-platform message overrides; leave blank to use the default message.",
        "properties": {
          "fb_message": { "type": "string", "description": "Facebook-specific message" },
          "tw_message": { "type": "string", "description": "X (Twitter)-specific message" },
          "ln_message": { "type": "string", "description": "LinkedIn-specific message" },
          "in_message": { "type": "string", "description": "Instagram-specific message" },
          "gmb_message": { "type": "string", "description": "Google Business Profile-specific message" },
          "pi_message": { "type": "string", "description": "Pinterest-specific message" },
          "yt_message": { "type": "string", "description": "YouTube-specific message" },
          "tk_message": { "type": "string", "description": "TikTok-specific message" },
          "th_message": { "type": "string", "description": "Threads-specific message" },
          "bs_message": { "type": "string", "description": "Bluesky-specific message" }
        }
      },
      "PlatformOptionFields": {
        "type": "object",
        "properties": {
          "fb_post_type": { "type": "string", "enum": ["feed", "story", "reel"], "default": "feed", "description": "Facebook post type" },
          "in_post_type": { "type": "string", "enum": ["feed", "story", "reel"], "default": "feed", "description": "Instagram post type" },
          "in_reel_share_in_feed": { "type": "string", "enum": ["yes", "no"], "default": "yes", "description": "Share Instagram Reel to feed too (only when in_post_type is reel)" },
          "first_comment": { "type": "string", "description": "Default first comment (commonly hashtags) for Facebook Pages, LinkedIn, and Instagram feed" },
          "fb_first_comment": { "type": "string", "description": "Facebook-specific first comment" },
          "ln_first_comment": { "type": "string", "description": "LinkedIn-specific first comment" },
          "in_first_comment": { "type": "string", "description": "Instagram-specific first comment (feed only)" },
          "ln_document": { "type": "string", "format": "uri", "description": "Document URL for LinkedIn carousel (PPT, PDF, DOCX)" },
          "ln_document_title": { "type": "string", "description": "Title for the LinkedIn document" },
          "pi_title": { "type": "string", "description": "Pinterest pin title" },
          "gbp_cta": { "type": "string", "enum": ["None", "Learn more", "Sign up", "Buy", "Order online", "Book", "Call now", "Offer"], "default": "None", "description": "Google Business Profile call-to-action button" },
          "gbp_cta_url": { "type": "string", "format": "uri", "description": "CTA link URL (not used for Call now or Offer)" },
          "gbp_offer_title": { "type": "string", "description": "Offer title (when CTA is Offer)" },
          "gbp_offer_start_date": { "type": "string", "description": "Offer start, format Y-m-d H:i:s" },
          "gbp_offer_end_date": { "type": "string", "description": "Offer end, format Y-m-d H:i:s" },
          "gbp_offer_coupon_code": { "type": "string", "description": "Coupon code for the offer" },
          "gbp_offer_terms": { "type": "string", "description": "Offer terms and conditions" },
          "gbp_redeem_offer_link": { "type": "string", "format": "uri", "description": "URL to redeem the offer" },
          "yt_title": { "type": "string", "description": "YouTube video title" },
          "yt_category": { "type": "string", "enum": ["Film & Animation", "Autos & Vehicles", "Music", "Pets & Animals", "Sports", "Travel & Events", "Gaming", "People & Blogs", "Comedy", "Entertainment", "News & Politics", "Howto & Style", "Education", "Science & Technology", "Nonprofits & Activism"], "default": "Entertainment", "description": "YouTube video category" },
          "yt_privacy_status": { "type": "string", "enum": ["Public", "Private", "Unlisted"], "default": "Public", "description": "YouTube privacy setting" },
          "yt_user_tags": { "type": "string", "description": "YouTube tags, comma-separated" },
          "yt_thumb": { "type": "string", "format": "uri", "description": "Custom YouTube thumbnail URL" },
          "yt_video_made_for_kids": { "type": "string", "enum": ["yes", "no"], "default": "yes", "description": "YouTube made-for-kids designation" },
          "tk_privacy_status": { "type": "string", "enum": ["Public to Everyone", "Mutual Follow Friends", "Self Only"], "default": "Public to Everyone", "description": "TikTok privacy setting" },
          "tk_allow_comments": { "type": "string", "enum": ["yes", "no"], "default": "yes", "description": "Allow TikTok comments" },
          "tk_allow_duet": { "type": "string", "enum": ["yes", "no"], "default": "yes", "description": "Allow TikTok duets" },
          "tk_allow_stitches": { "type": "string", "enum": ["yes", "no"], "default": "yes", "description": "Allow TikTok stitches" }
        }
      },
      "AddLibraryContentRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/AuthOnly" },
          {
            "type": "object",
            "required": ["id", "message"],
            "properties": {
              "id": { "type": "string", "description": "Library ID from /api/library_list" },
              "message": { "type": "string", "description": "Default message/content for the post" },
              "is_top_of_queue": { "type": "integer", "enum": [0, 1], "default": 0, "description": "1 moves the post to the top of the queue on all selected accounts" },
              "content_livedate": { "type": "string", "format": "date", "description": "Keep as draft until this date (YYYY-MM-DD); blank = active immediately" },
              "content_expiredate": { "type": "string", "format": "date", "description": "Stop recurring after this date (YYYY-MM-DD); blank = never expires" }
            }
          },
          { "$ref": "#/components/schemas/MediaFields" },
          { "$ref": "#/components/schemas/PlatformMessageFields" },
          { "$ref": "#/components/schemas/PlatformOptionFields" }
        ]
      },
      "PostContentRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/AuthOnly" },
          {
            "type": "object",
            "required": ["id", "message"],
            "properties": {
              "id": { "type": "string", "description": "Social account ID from /api/social_account_list" },
              "message": { "type": "string", "description": "Message/content for the post" },
              "schedule_date_time": { "type": "string", "description": "Future publish time, format YYYY-MM-DD HH:MM:SS; blank posts immediately. Past times return error 415." }
            }
          },
          { "$ref": "#/components/schemas/MediaFields" },
          { "$ref": "#/components/schemas/PlatformMessageFields" },
          { "$ref": "#/components/schemas/PlatformOptionFields" }
        ]
      },
      "GenerateContentRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/AuthOnly" },
          {
            "type": "object",
            "required": ["prompt_text"],
            "properties": {
              "prompt_text": { "type": "string", "description": "Topic or instruction to generate content about" },
              "ai_id": { "type": "string", "description": "AI session ID from a previous response, to continue the conversation" },
              "chat_progress": { "type": "string", "description": "Progress marker from a previous response" },
              "chat_history": { "type": "array", "items": { "type": "object" }, "description": "Previous conversation messages with roles (user/assistant) and content" }
            }
          }
        ]
      },
      "GenerateImageRequest": {
        "allOf": [
          { "$ref": "#/components/schemas/AuthOnly" },
          {
            "type": "object",
            "required": ["prompt_text"],
            "properties": {
              "prompt_text": { "type": "string", "description": "Detailed description of the image to generate" }
            }
          }
        ]
      }
    }
  }
}
