{
  "openapi": "3.1.0",
  "info": {
    "title": "uplika",
    "version": "1.0.0",
    "description": "Publish to social channels from your own code. If you would rather have an AI agent do it, connect over MCP instead and skip API keys entirely.",
    "contact": {
      "url": "https://uplika.com/en/docs"
    }
  },
  "servers": [
    {
      "url": "https://api.uplika.com"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from the dashboard."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "verification_required",
                  "next_post_taken",
                  "past_comments_not_supported",
                  "past_comments_no_trigger",
                  "automation_not_live",
                  "past_comments_no_post",
                  "past_comments_running",
                  "scheduled_at_invalid",
                  "scheduled_at_range",
                  "draft_and_schedule",
                  "batch_id_invalid",
                  "naver_source_required",
                  "naver_keep_unknown",
                  "post_not_editable",
                  "live_post_no_schedule",
                  "live_post_accounts_fixed",
                  "nothing_to_change",
                  "target_required",
                  "thread_piece",
                  "naver_draft_not_found",
                  "account_required",
                  "invalid_api_key",
                  "forbidden_scope",
                  "no_accounts",
                  "empty_content",
                  "account_not_connected",
                  "account_expired",
                  "platform_not_available",
                  "content_too_long",
                  "media_required",
                  "media_mixed",
                  "media_too_many",
                  "media_too_large",
                  "media_aspect_ratio",
                  "media_dimensions",
                  "media_type_not_supported",
                  "media_too_long",
                  "media_url_invalid",
                  "media_url_blocked",
                  "media_url_unreachable",
                  "media_unreachable",
                  "workspace_required",
                  "workspace_mismatch",
                  "workspace_limit",
                  "platform_already_connected",
                  "quota_exceeded",
                  "workspaces_invalid",
                  "billing_not_configured",
                  "full_access_open",
                  "checkout_failed",
                  "no_subscription",
                  "portal_failed",
                  "media_not_uploaded",
                  "media_expired",
                  "media_not_publishable",
                  "media_in_use",
                  "media_delete_failed",
                  "media_store_failed",
                  "upload_bytes_missing",
                  "api_unreachable",
                  "naver_media_kind_mismatch",
                  "naver_media_over_limit",
                  "media_ref_unknown",
                  "media_ref_not_supported",
                  "media_not_configured",
                  "post_not_found",
                  "media_not_found",
                  "key_not_found",
                  "grant_not_found",
                  "nothing_to_retry",
                  "not_published",
                  "delete_window_expired",
                  "platform_error",
                  "duplicate_post",
                  "unauthenticated",
                  "platform_rejected_content",
                  "platform_auth_error",
                  "topic_tag_invalid",
                  "youtube_video_not_replaceable",
                  "topic_tag_not_supported",
                  "api_key_revoked",
                  "api_key_expired",
                  "idempotency_key_reused",
                  "publish_in_flight",
                  "extension_outdated",
                  "thread_and_content",
                  "thread_empty",
                  "container_expired",
                  "permission_denied",
                  "invalid_json",
                  "body_too_large",
                  "internal_error",
                  "system_error",
                  "rate_limited",
                  "account_not_found",
                  "account_has_pending_posts",
                  "account_disconnected",
                  "post_unavailable",
                  "post_deleted",
                  "account_busy_publishing",
                  "empty_reply",
                  "cannot_hide_own_reply",
                  "media_fields_required",
                  "not_our_post",
                  "key_name_required",
                  "key_scope_required",
                  "invalid_locale",
                  "url_required",
                  "reference_invalid",
                  "reference_not_naver",
                  "reference_not_public",
                  "reference_not_readable",
                  "reference_too_large",
                  "reference_timeout",
                  "reference_unreachable",
                  "reference_not_read",
                  "bad_post_ref",
                  "post_not_owned",
                  "post_not_in_recent",
                  "upload_session_not_found",
                  "upload_session_full",
                  "media_url_invalid",
                  "media_url_blocked",
                  "media_url_unreachable",
                  "workspace_required",
                  "workspace_mismatch",
                  "workspace_limit",
                  "platform_already_connected",
                  "quota_exceeded",
                  "workspaces_invalid",
                  "billing_not_configured",
                  "full_access_open",
                  "checkout_failed",
                  "no_subscription",
                  "portal_failed",
                  "youtube_title_required",
                  "youtube_title_too_long",
                  "youtube_angle_brackets",
                  "youtube_video_required",
                  "youtube_tags_too_long",
                  "youtube_schedule_needs_private",
                  "youtube_schedule_invalid",
                  "youtube_thumbnail_type",
                  "youtube_thumbnail_too_large",
                  "youtube_short_no_thumbnail",
                  "youtube_no_threads",
                  "instagram_reel_video_required",
                  "instagram_reel_duration",
                  "instagram_story_single_media",
                  "instagram_story_no_extras",
                  "instagram_story_duration",
                  "instagram_cover_reel_only",
                  "instagram_cover_type",
                  "instagram_cover_too_large",
                  "instagram_too_many_collaborators",
                  "instagram_user_tag_position",
                  "facebook_link_with_media",
                  "facebook_link_invalid",
                  "facebook_reel_video_required",
                  "facebook_reel_duration",
                  "facebook_story_single_media",
                  "facebook_story_no_extras",
                  "facebook_story_no_caption",
                  "facebook_schedule_feed_only",
                  "facebook_schedule_invalid",
                  "facebook_schedule_range",
                  "facebook_targeting_text_only",
                  "facebook_targeting_not_editable",
                  "facebook_schedule_no_first_comment",
                  "threads_not_supported",
                  "beta_access_required",
                  "naver_title_required",
                  "naver_title_too_long",
                  "naver_category_required",
                  "naver_markdown_unknown",
                  "naver_category_unknown",
                  "naver_category_ambiguous",
                  "naver_form_unknown",
                  "naver_form_required",
                  "content_required",
                  "help_not_found",
                  "invalid_locale",
                  "invalid_category",
                  "invalid_topic",
                  "naver_wrong_blog",
                  "naver_wrong_login",
                  "naver_session_permission",
                  "naver_rate_limited",
                  "naver_not_allowed",
                  "naver_follow_blocked",
                  "naver_comment_gone",
                  "upload_stalled",
                  "platform_timeout",
                  "naver_draft_unpublished",
                  "naver_stats_unavailable",
                  "naver_comments_closed",
                  "naver_post_unavailable",
                  "naver_card_unavailable",
                  "naver_card_not_inserted",
                  "naver_tab_lost",
                  "naver_draft_unknown",
                  "naver_reply_unknown",
                  "naver_publish_unconfirmed",
                  "comments_closed",
                  "refresh_unsupported",
                  "invalid_params",
                  "quota_exceeded",
                  "naver_seo_unavailable",
                  "naver_api_error",
                  "invalid_blog_id",
                  "blog_not_found",
                  "naver_rss_unreachable",
                  "naver_autocomplete_unavailable",
                  "naver_autocomplete_paused",
                  "naver_autocomplete_busy",
                  "research_tool_disabled",
                  "research_quota_exceeded",
                  "youtube_quota_exhausted",
                  "youtube_search_unavailable",
                  "naver_seo_busy",
                  "refresh_timeout",
                  "refresh_failed",
                  "naver_reply_media_not_supported",
                  "naver_too_many_tags",
                  "naver_tag_too_long",
                  "naver_tag_has_space",
                  "naver_scheduled_at_conflict",
                  "naver_scheduled_at_mixed",
                  "naver_draft_and_schedule",
                  "naver_font_size_out_of_range",
                  "naver_ui_changed",
                  "naver_not_logged_in",
                  "naver_upload_failed",
                  "naver_publish_failed",
                  "naver_verify_failed",
                  "bridge_unsupported",
                  "bridge_lost",
                  "bridge_stalled",
                  "bridge_timeout",
                  "naver_category_missing",
                  "naver_grammar_rejected",
                  "platform_activity_blocked",
                  "youtube_daily_cap",
                  "bridge_offline",
                  "account_required",
                  "not_supported",
                  "reconsent_required",
                  "feature_in_review",
                  "tiktok_privacy_required",
                  "tiktok_privacy_invalid",
                  "tiktok_branded_private",
                  "tiktok_interaction_disabled",
                  "tiktok_title_required",
                  "tiktok_title_too_long",
                  "tiktok_title_not_supported",
                  "tiktok_cannot_post",
                  "tiktok_reply_not_supported"
                ]
              },
              "message": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        }
      }
    }
  },
  "security": [
    {
      "apiKey": []
    }
  ],
  "externalDocs": {
    "url": "https://uplika.com/en/docs",
    "description": "Reference, error codes and per-channel limits."
  },
  "paths": {
    "/v1/help": {
      "get": {
        "summary": "Troubleshooting answers by error code, question or id. No authentication.",
        "tags": [
          "Troubleshooting and FAQ"
        ],
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "required": false,
            "description": "An error code, e.g. reconsent_required. Returns the answers for that code.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "A short question in any language. Returns the five best matches.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "One answer by its id, e.g. thread-control.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "platform",
            "in": "query",
            "required": false,
            "description": "Only answers about this platform, plus general ones.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "dm, connect, publish, naver or agent.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "locale",
            "in": "query",
            "required": false,
            "description": "en (default) or ko.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/accounts": {
      "get": {
        "summary": "Once connected, the account shows up in GET /v1/accounts with an id. That id is what publishing takes.",
        "tags": [
          "Connecting channels"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/posts": {
      "get": {
        "summary": "Recent publishes, newest first. Replies are not listed as posts.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-100, defaults to 20.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "A publish id from a previous page's nextBefore. Returns the ones older than it.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeDeleted",
            "in": "query",
            "required": false,
            "description": "true brings back posts you deleted from the channel. They are hidden by default. Our record and its metrics stay either way.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Narrow to one or more statuses, comma separated: scheduled, draft, publishing, published, partial, failed or cancelled. Omit for everything, scheduled and draft included.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "YYYY-MM-DD or ISO 8601. Posts dated at or after this. A scheduled post is dated by scheduledAt, a sent one by when it was created.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "YYYY-MM-DD or ISO 8601. Posts dated at or before this; a date means the whole day.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "scheduled orders by the post's date ascending and drops paging. Omit for newest first.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Publish to one or more connected accounts.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {
                    "type": "string",
                    "description": "Post text. Emoji count as UTF-8 bytes."
                  },
                  "accountIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Ids from GET /v1/accounts."
                  },
                  "mediaIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Media already confirmed with complete. On Naver Blog you may leave out ids the body already points at with media:<id>; we read those from the text and attach them."
                  },
                  "options": {
                    "type": "object",
                    "description": "Per-channel settings, keyed by the channel id. The shape is in GET /v1/platforms under options and on each channel page. Some channels cannot publish without it — YouTube needs options.youtube.title and Naver Blog needs options.naver_blog.title plus a category. Every channel takes options.<channel>.content, a different text for that channel alone."
                  },
                  "scheduledAt": {
                    "type": "string",
                    "description": "ISO 8601 with a timezone offset, 10 minutes to a year out. We keep the post as scheduled and send it at that time, on every channel."
                  },
                  "draft": {
                    "type": "boolean",
                    "description": "true saves the post without sending. It can have no accountIds yet. Send it later with POST /v1/posts/{id}/publish."
                  },
                  "batchId": {
                    "type": "string",
                    "description": "Optional tag, up to 40 characters, to group posts made together (for example the same text sent to two workspaces). Comes back on every post."
                  },
                  "replyTo": {
                    "type": "string",
                    "description": "Publish this as a reply to that post id."
                  },
                  "threadItems": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "Split a long post into a chain: [{ content, mediaIds? }]. The first item is the root, the rest become replies under it in order. Each item obeys the character limit on its own. Exclusive with content. Only Threads and Bluesky take a chain; the composer builds one with the item editor. If a later item fails the ones already up stay up, and the response carries thread.resumeFrom. Posts that have later items carry them back as threadItems, and PATCH takes the same field while the post is scheduled or a draft."
                  },
                  "topicTag": {
                    "type": "string",
                    "description": "One topic to tag the post with. Threads takes exactly one and rejects periods and ampersands. On a thread it applies to the first piece only."
                  },
                  "Idempotency-Key": {
                    "type": "string",
                    "description": "Send the same key when you retry and we return the first answer instead of publishing twice. Reusing a key with a different body is a 422. Kept for 24 hours."
                  },
                  "wait": {
                    "type": "boolean",
                    "description": "Hold the response until the post is really out. Text waits up to 10 seconds, media up to 75. Past that you get the usual 202 with a next hint, and the post keeps going. Defaults to false."
                  }
                },
                "required": [
                  "content",
                  "accountIds"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/posts/{id}": {
      "get": {
        "summary": "One publish with the status of each target.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Change a scheduled or draft post before it goes out. Fields you leave out keep their value, except that a post going only to Naver Blog takes its media list from the new body's media: references when you leave mediaIds out; options replaces the whole object; threadItems replaces a chain, content alone edits its first item. Editing a post that is already live is asynchronous: wait: true holds the response for the result (up to 75 seconds), and past that it answers 202 with next telling you to read the post. A Naver draft save that went quiet is looked up in Naver's draft list and recovered when it is there.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {
                    "type": "string",
                    "description": "New post text."
                  },
                  "accountIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "New target accounts. Replaces the current set."
                  },
                  "mediaIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "New media, in order. Replaces the current set. On a post going only to Naver Blog, leave it out when the body places media with media: references: those references become the list and media the new body does not place is removed (the response note says how many)."
                  },
                  "options": {
                    "type": "object",
                    "description": "Per-channel settings. Replaces the whole object."
                  },
                  "scheduledAt": {
                    "type": "string",
                    "description": "New send time, same rules as on create. null turns the post into a draft."
                  },
                  "draft": {
                    "type": "boolean",
                    "description": "true turns a scheduled post back into a draft."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete the post from the channel and mark our record deleted.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/posts/{id}/publish": {
      "post": {
        "summary": "Send a scheduled or draft post right now. Same function the scheduler runs, so it cannot go out twice.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "wait": {
                    "type": "boolean",
                    "description": "Hold the response until the post is really out, same as on create."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/posts/{id}/retry": {
      "post": {
        "summary": "Retry the targets that failed. Targets that already went out are skipped. A Naver target that stopped right after Save as draft (naver_draft_unknown) or a Naver reply that did not confirm in time (naver_reply_unknown) answers 409 until the body carries {\"force\": true}. If another post with the same content and files is already on the same account, it answers 409 duplicate_post with that post's id and retries nothing; {\"force\": true} sends it anyway.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/posts/{id}/thread": {
      "get": {
        "summary": "One post with its replies and metrics in a single call.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/channels/posts": {
      "get": {
        "summary": "What is on the channel right now, including posts written in the app.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "description": "Limit to one connected account. Omit to cover every channel.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-100, defaults to 25.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/channels/quota": {
      "get": {
        "summary": "How much of the 24 hour allowance the channel says is used.",
        "tags": [
          "Posts"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/channels/bridge": {
      "get": {
        "summary": "Whether the Naver Blog bridge (browser extension) is online, and how to wake Chrome if it is not.",
        "tags": [
          "Posts"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/channels/publish-options": {
      "get": {
        "summary": "What a channel needs to know before you publish to it. TikTok only: the creator nickname the post goes out as, the privacy levels this account may use right now, whether it can post at all, and its video length limit. Other channels return not_supported.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "description": "Required. These values are per connected account and change when the person edits their channel settings, so do not cache them.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "accountId": {
                    "type": "string",
                    "description": "Required. These values are per connected account and change when the person edits their channel settings, so do not cache them."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/accounts/select": {
      "post": {
        "summary": "Pick which connected channels to publish to.",
        "tags": [
          "Posts"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/accounts/:id/refresh": {
      "post": {
        "summary": "Re-read a channel's metadata, such as Naver Blog categories. Waits up to a minute for the browser extension.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "scope": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Omit to list candidates. \"all\" for every active channel, or an array mixing platform names, handles and account ids."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/blog/diagnose": {
      "get": {
        "summary": "Read a Naver blog's public RSS feed (its latest posts, at most 50) and say whether the titles are written for search: the share of titles carrying a search intent word (price, how to, review), how many start with a date or episode label, posts per month, the categories, and the words the blog repeats in titles (candidates to research, not proven keywords). The response carries the date range it read, so a quiet blog's 50 posts are not mistaken for everything. Cached 24 hours across users; a cache miss spends one of 20 diagnoses per person per day. No Naver API keys are needed.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "blog": {
                    "type": "string",
                    "description": "A Naver blog id (2-40 letters, digits, - or _) or any link to the blog: blog.naver.com/<id>, m.blog.naver.com/<id>/<logNo>, PostView.naver?blogId=<id>."
                  }
                },
                "required": [
                  "blog"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/keywords/judge": {
      "post": {
        "summary": "Measure Naver search keywords and pick a set for one post. Expands nothing; send the keywords you have. Returns monthly searches (Search Ad), blog document count and posts per month (API HUB), a verdict per keyword, and sets of one main keyword plus two to five sub keywords with the same intent. Results are cached for seven days across users; 30 calls and 300 measured keywords per user per day.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keywords": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Required. 1-300 keywords. Spaces are fine; the numbers come back per keyword as you sent it."
                  },
                  "save": {
                    "type": "boolean",
                    "description": "Default false. true stores this research as a report (the keywords, the first set's main and subs, every set with its prompt) and returns reportId. The same person sending the same keyword set within ten minutes gets the existing reportId back with no new row and no judge call spent."
                  },
                  "seedText": {
                    "type": "string",
                    "description": "What the person typed, kept with the saved report as its label. Defaults to the first five keywords."
                  },
                  "cacheOnly": {
                    "type": "boolean",
                    "description": "Default false. true never calls Naver: keywords without a fresh cached value come back in unmeasured with no numbers. Use it after measuring in chunks, so the judge call is instant and spends nothing upstream."
                  },
                  "budgetMs": {
                    "type": "number",
                    "description": "Time budget for new measurements, default and maximum 60000. When it runs out, no new upstream call starts; the response says partial: true and lists unmeasured. Call again and the cached part is skipped."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/keywords/measure": {
      "post": {
        "summary": "Same measurement without the verdict and sets. withDocs:false skips document counts.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keywords": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Required. 1-300 keywords. At most 40 of them are measured fresh in one call; the rest come back in unmeasured and are picked up by the next call."
                  },
                  "withDocs": {
                    "type": "boolean",
                    "description": "Default true. false measures search volume only."
                  },
                  "budgetMs": {
                    "type": "number",
                    "description": "Time budget for new measurements, default and maximum 60000. Past it the call stops starting upstream requests and returns partial: true with unmeasured."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/keywords/expand": {
      "post": {
        "summary": "Expand seed keywords one level through Naver autocomplete, for agents and API keys (the dashboard does this in your browser). When the person's uplika Chrome extension is on, it looks the seeds up in the background from their own connection; otherwise our server does. Returns every word found with which seed produced it, and via says which path answered. When neither can run this answers 503 naver_autocomplete_unavailable, and you should pass your own keyword list to judge instead.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "seeds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Required. 1-10 seed keywords. Each is sent to Naver autocomplete once (one level); the words that come back are candidates to measure with judge, not proven keywords. Cached seven days across users. No daily quota: when the person's uplika Chrome extension answers there is no wait, and when our server answers, one call per person every 60 seconds (naver_autocomplete_busy with retryAfterSeconds)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/keywords/reports": {
      "get": {
        "summary": "List the keyword research you saved (judge with save: true), newest first: when, what you typed, the first set's main and sub keywords, and every set with its ready-to-paste prompt. Reports belong to the person, so an API key limited to some workspaces gets 403.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "limit": {
                    "type": "number",
                    "description": "Default 50, newest first."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/keywords/history": {
      "get": {
        "summary": "The measurement history of one keyword: one point per day it was actually measured (cache hits add nothing), newest first, with search volume, document count and posts per month. An empty list is 200 with data: [].",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keyword": {
                    "type": "string",
                    "description": "The keyword, as you would send it to measure. A query parameter, since keywords are usually Korean."
                  },
                  "limit": {
                    "type": "number",
                    "description": "Default 100 days, newest first."
                  }
                },
                "required": [
                  "keyword"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/research/youtube/search": {
      "get": {
        "summary": "Search YouTube for a keyword and get the top videos with views, subscribers, length and publish date as YouTube gives them, the views-to-subscribers ratio and Shorts or long-form (both calculated by uplika, not YouTube metrics; dataNotes says so), plus a ready-to-paste prompt for titles and hooks in the person's Uplika language (Korean or English). The same search is cached 24 hours and does not count; a new one spends one of the person's daily searches (quota in the response) and shared YouTube Data API units. Saved to the person's history with reportId.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "q": {
                    "type": "string",
                    "description": "The search words, as a viewer would type them."
                  },
                  "order": {
                    "type": "string",
                    "description": "viewCount (default), date or relevance."
                  },
                  "period": {
                    "type": "string",
                    "description": "7d, 1m, 3m, 6m or 1y. Omit for no limit."
                  },
                  "format": {
                    "type": "string",
                    "description": "all (default), shorts or long. 60 seconds or less counts as a Short."
                  },
                  "max": {
                    "type": "number",
                    "description": "1-50, default 25."
                  },
                  "topic": {
                    "type": "string",
                    "description": "The video the person wants to make, one line. Goes into prompt and is saved with the report."
                  }
                },
                "required": [
                  "q"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/research/youtube/reports": {
      "get": {
        "summary": "The person's saved YouTube searches, newest first: when, the search and its filters, the topic, how many videos and whether it came from cache. Results are kept for up to 30 days, then deleted.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "limit": {
                    "type": "number",
                    "description": "Default 50, newest first."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/research/youtube/reports/{id}": {
      "get": {
        "summary": "One saved search with the videos as they were and the prompt built from them.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/seo/check": {
      "post": {
        "summary": "Run the Naver Blog placement checks on a Markdown body before publishing: section titles match the sub keywords one to one, the main keyword appears 3-5 times, 12-15 tags all present in the body, no product names in the first three paragraphs, every attached image placed with a caption of ten or more characters, and a body length floor. Nothing is blocked; the report says what is off and why.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {
                    "type": "string",
                    "description": "Required. The Markdown body, up to 60,000 characters."
                  },
                  "title": {
                    "type": "string",
                    "description": "The post title."
                  },
                  "main": {
                    "type": "string",
                    "description": "The main keyword. Without it the keyword checks cannot pass."
                  },
                  "subs": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Sub keywords, one per section title."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "The tags you will send in options.naver_blog.tags."
                  },
                  "fixedTags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Tags that need not appear in the body (brand tags)."
                  },
                  "products": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Product and brand names that must stay out of the first three paragraphs."
                  },
                  "mediaIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "The media ids attached to the post, to check that each is placed."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/layout": {
      "post": {
        "summary": "See how a body will be laid out before publishing. The same pass publish runs by default (layout: template), returned without sending anything; forms: \"all\" lays it out in every preset so a person can pick one.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {
                    "type": "string",
                    "description": "The markdown body to lay out."
                  },
                  "mediaIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Attached media, in order. Images the body does not reference are placed by the form."
                  },
                  "form": {
                    "type": "string",
                    "description": "One preset id (default photo-story). Ignored when forms is given."
                  },
                  "forms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Lay the same body out in several presets at once; the response carries layouts[] so a person can compare and pick."
                  }
                },
                "required": [
                  "content"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/forms": {
      "get": {
        "summary": "The seven post forms we ship. A form is the shape of a post: what opens a section, whether a quotation is a heading or a quoted passage, how often a sentence is highlighted, how many images per section, whether images get captions. Each one was measured from a real published post. Pass an id to options when generating; the form only shapes what we ask the model for, and never touches publishing.",
        "tags": [
          "Posts"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/drafts": {
      "get": {
        "summary": "The drafts in the blog's draft box: posts saved with draftOnly and anything saved by hand in the Naver editor. Extension 0.7.2 or later.",
        "tags": [
          "Posts"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/drafts/{logNo}/publish": {
      "post": {
        "summary": "Publishes a draft from the draft box exactly as it is in Naver: the extension loads it in the editor and presses publish, so hand edits are kept. Same response shape as POST /v1/posts; if uplika made that draft, that post record flips to published.",
        "tags": [
          "Posts"
        ],
        "parameters": [
          {
            "name": "logNo",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "logNo": {
                    "type": "string",
                    "description": "The draft's id from GET /v1/naver/drafts."
                  },
                  "accountId": {
                    "type": "string",
                    "description": "Required only when the workspace has more than one Naver Blog account."
                  },
                  "title / categoryId / category / tags / openType": {
                    "type": "string",
                    "description": "Override the draft's own values. Left out, the draft goes out as it is."
                  },
                  "wait": {
                    "type": "boolean",
                    "description": "Hold until the extension finishes, up to 75 seconds like a post with media on POST /v1/posts. Past that you get the usual 202 with a next hint, and the draft keeps going out."
                  }
                },
                "required": [
                  "logNo"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/grammar": {
      "get": {
        "summary": "What the Naver Blog body understands: directives, block and inline markup, attributes, highlights, media references and the limits. This is the same guide the describe_grammar tool returns, and the values come from one source, so it never drifts from what the editor actually accepts. Pass topic to read one section.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "topic": {
                    "type": "string",
                    "description": "One section instead of the whole guide. The 400 lists the ids."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/forms/extract": {
      "post": {
        "summary": "Read a public Naver Blog post and hand back its form. We take the structure and the formatting, never the words or the photos. Use it for \"write it like this post\". We keep what we read, so AI generation uses that saved form and never goes back to Naver. Call it again to pick up changes in the reference.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Required. A public Naver Blog post, like https://blog.naver.com/someone/224349824125. Only blog.naver.com links work, and private or deleted posts are refused. Five per minute."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/naver/forms/snapshot": {
      "get": {
        "summary": "When a reference post was last read, and how many blocks and photos it had. Reads our saved copy only.",
        "tags": [
          "Posts"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Required. The same post link you passed to extract. Answers from our database only; Naver is not called. 404 reference_not_read when it was never read."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/posts/{id}/replies": {
      "get": {
        "summary": "The reply thread under a published post.",
        "tags": [
          "Replies and insights"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Reply to the post, or to a reply under it.",
        "tags": [
          "Replies and insights"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {
                    "type": "string",
                    "description": "Reply text."
                  },
                  "replyTo": {
                    "type": "string",
                    "description": "A reply id from the thread. Omit to answer the post itself."
                  },
                  "wait": {
                    "type": "boolean",
                    "description": "Hold the response until the reply is out, up to 10 seconds. Answers 200 with the post when it settles, otherwise 202 with next."
                  }
                },
                "required": [
                  "content"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/engagement/like": {
      "post": {
        "summary": "Like a post, or a reply under it. Idempotent; there is no unlike.",
        "tags": [
          "Replies and insights"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "postId": {
                    "type": "string",
                    "description": "Your own publish. Or pass ownerHandle and externalId instead."
                  },
                  "ownerHandle": {
                    "type": "string",
                    "description": "Who owns the post. Naver Blog: the blog id."
                  },
                  "externalId": {
                    "type": "string",
                    "description": "The post's id on the channel. Naver Blog: the logNo from the link."
                  },
                  "replyId": {
                    "type": "string",
                    "description": "A reply id from the thread to like that reply instead of the post."
                  },
                  "accountId": {
                    "type": "string",
                    "description": "Which connected account acts. Only needed with more than one account on that channel."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/engagement/reply": {
      "post": {
        "summary": "Reply to a post that is not yours (Naver Blog). No publish record is created.",
        "tags": [
          "Replies and insights"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ownerHandle": {
                    "type": "string",
                    "description": "Who owns the post."
                  },
                  "externalId": {
                    "type": "string",
                    "description": "The post's id on the channel."
                  },
                  "content": {
                    "type": "string",
                    "description": "Reply text."
                  },
                  "replyId": {
                    "type": "string",
                    "description": "Reply under this reply instead of under the post."
                  },
                  "secret": {
                    "type": "boolean",
                    "description": "Naver Blog: a secret comment only the blog owner can read."
                  }
                },
                "required": [
                  "ownerHandle",
                  "externalId",
                  "content"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/engagement/follow": {
      "post": {
        "summary": "Follow an account (Naver Blog: add as neighbor). mutual sends a request the other side accepts.",
        "tags": [
          "Replies and insights"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ownerHandle": {
                    "type": "string",
                    "description": "The account to follow. Naver Blog: the blog id."
                  },
                  "mutual": {
                    "type": "boolean",
                    "description": "Naver Blog: send a mutual-neighbor request instead. Comes back pending until accepted."
                  },
                  "message": {
                    "type": "string",
                    "description": "Sent with a mutual request. Up to 500 characters."
                  },
                  "accountId": {
                    "type": "string",
                    "description": "Which connected account acts."
                  }
                },
                "required": [
                  "ownerHandle"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/replies/{replyId}/hide": {
      "post": {
        "summary": "Hide a reply on the channel, or show it again.",
        "tags": [
          "Replies and insights"
        ],
        "parameters": [
          {
            "name": "replyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "postId": {
                    "type": "string",
                    "description": "The publish the reply sits under."
                  },
                  "hide": {
                    "type": "boolean",
                    "description": "true hides it, false shows it again. Default true."
                  }
                },
                "required": [
                  "postId"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/replies/{replyId}": {
      "delete": {
        "summary": "Delete a comment for good. Unlike hide, this cannot be undone, and which channels have it at all is in features on GET /v1/platforms.",
        "tags": [
          "Replies and insights"
        ],
        "parameters": [
          {
            "name": "replyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "postId": {
                    "type": "string",
                    "description": "The publish the reply sits under."
                  }
                },
                "required": [
                  "postId"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/posts/{id}/insights": {
      "get": {
        "summary": "Views, likes, replies, reposts, quotes and shares.",
        "tags": [
          "Replies and insights"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/media/presign": {
      "post": {
        "summary": "Ask for an upload URL and a media id.",
        "tags": [
          "Media"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fileName": {
                    "type": "string",
                    "description": "Original file name."
                  },
                  "contentType": {
                    "type": "string",
                    "description": "image/jpeg, image/png, image/webp, image/gif"
                  },
                  "bytes": {
                    "type": "number",
                    "description": "File size in bytes."
                  },
                  "width": {
                    "type": "number",
                    "description": "Pixel width, if you know it."
                  },
                  "height": {
                    "type": "number",
                    "description": "Pixel height, if you know it."
                  },
                  "altText": {
                    "type": "string",
                    "description": "What the image shows, for screen readers. Applied to carousel items."
                  },
                  "aiGenerated": {
                    "type": "boolean",
                    "description": "true when the file was generated or substantially changed with AI. Naver Blog photos get the AI usage label, and Instagram, YouTube and TikTok get their AI declaration unless the post sets it to false."
                  }
                },
                "required": [
                  "fileName",
                  "contentType",
                  "bytes"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/media/{id}/complete": {
      "post": {
        "summary": "Confirm the upload. We check the object really exists.",
        "tags": [
          "Media"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/media/{id}": {
      "delete": {
        "summary": "Remove a media item you uploaded by mistake. Anything a post still uses, or an original a copy in another workspace still shares, answers 409.",
        "tags": [
          "Media"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Mark or clear the AI-made flag. Every copy of the same file in your workspaces follows. Posts already out do not change.",
        "tags": [
          "Media"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "aiGenerated": {
                    "type": "boolean",
                    "description": "true when the file was generated or substantially changed with AI. Naver Blog photos get the AI usage label, and Instagram, YouTube and TikTok get their AI declaration unless the post sets it to false."
                  }
                },
                "required": [
                  "aiGenerated"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/media/from-url": {
      "post": {
        "summary": "Copy a public file into your workspace in one call.",
        "tags": [
          "Media"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Public https URL of the file itself."
                  },
                  "altText": {
                    "type": "string",
                    "description": "What the image shows, for screen readers."
                  },
                  "aiGenerated": {
                    "type": "boolean",
                    "description": "true when the file was generated or substantially changed with AI. Naver Blog photos get the AI usage label, and Instagram, YouTube and TikTok get their AI declaration unless the post sets it to false."
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/templates": {
      "get": {
        "summary": "Every template: its id, channels, parameters (JSON Schema) and the reviewed feature it needs, if any.",
        "tags": [
          "Automations"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/capabilities": {
      "get": {
        "summary": "Per channel: which triggers and steps a flow may use there.",
        "tags": [
          "Automations"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/quick/{template}": {
      "post": {
        "summary": "Create a flow from a template and its parameters. The usual way.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "template",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "template": {
                    "type": "string",
                    "description": "A template id from GET /v1/automations/templates, e.g. comment_to_dm, comment_public_reply, keyword_dm, default_reply."
                  },
                  "accountId": {
                    "type": "string",
                    "description": "The connected account the flow runs on."
                  },
                  "params": {
                    "type": "object",
                    "description": "The template's parameters. Their schema is in the template's params."
                  },
                  "enabled": {
                    "type": "boolean",
                    "description": "true to turn it on right away. Defaults to false (a draft)."
                  },
                  "name": {
                    "type": "string",
                    "description": "Defaults to the template's title."
                  }
                },
                "required": [
                  "template",
                  "accountId",
                  "params"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations": {
      "post": {
        "summary": "Create a flow from a full document.",
        "tags": [
          "Automations"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "accountId": {
                    "type": "string",
                    "description": "The connected account the flow runs on."
                  },
                  "doc": {
                    "type": "object",
                    "description": "The flow document: triggers and nodes. POST /v1/automations/validate checks it first."
                  },
                  "name": {
                    "type": "string",
                    "description": "Defaults to Untitled automation."
                  },
                  "enabled": {
                    "type": "boolean",
                    "description": "Defaults to false."
                  },
                  "postId": {
                    "type": "string",
                    "description": "Ties the flow to one of your posts."
                  }
                },
                "required": [
                  "accountId",
                  "doc"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "Every flow in the workspace, newest first.",
        "tags": [
          "Automations"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/validate": {
      "post": {
        "summary": "Check a document without saving it. Answers the list of problems, empty when it is fine.",
        "tags": [
          "Automations"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}": {
      "get": {
        "summary": "One flow with its document, version, run counts and the channel's capabilities.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Replace the document. Send the version you read; a newer save answers 409 version_conflict.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "version": {
                    "type": "number",
                    "description": "The version you read. A newer save answers 409 version_conflict with the current version."
                  },
                  "doc": {
                    "type": "object",
                    "description": "The new document. Or send template instead."
                  },
                  "template": {
                    "type": "object",
                    "description": "{ id, params }: rebuild the document from a template, as the dashboard wizard does."
                  },
                  "name": {
                    "type": "string",
                    "description": "A new name."
                  }
                },
                "required": [
                  "version"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Rename, or turn on and off with enabled.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete the flow, its runs and its versions.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}/enable": {
      "post": {
        "summary": "Turn it on. From this moment messages go to real people.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}/disable": {
      "post": {
        "summary": "Turn it off. Runs that are waiting do not continue.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}/duplicate": {
      "post": {
        "summary": "Copy it as a new draft, with the same document and template parameters.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}/past-comments/preview": {
      "post": {
        "summary": "Count without sending: how many comments would get the flow, and why the others would not. Takes the same body as the start call.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}/past-comments": {
      "post": {
        "summary": "Start sending. Answers 202 with the job; one job per flow at a time.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "includeAnswered": {
                    "type": "boolean",
                    "description": "Also send to comments that already have a reply from the account. Defaults to false."
                  },
                  "publicReply": {
                    "type": "boolean",
                    "description": "Also post the trigger's public reply under each comment. Defaults to false."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "The most recent job: its status, how many were sent, and how many are queued. GET /v1/automations/{id} carries the same in pastComments.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Stop the running job. Comments already answered stay answered.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}/runs": {
      "get": {
        "summary": "What happened each time it fired: status, the reason it stopped, and a step log.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-200, defaults to 50.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "A run id from the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "limit": {
                    "type": "string",
                    "description": "1-200, defaults to 50."
                  },
                  "before": {
                    "type": "string",
                    "description": "A run id from the previous page."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}/versions": {
      "get": {
        "summary": "Saved versions of the document, newest first.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/automations/{id}/versions/{version}": {
      "get": {
        "summary": "One saved version of the document.",
        "tags": [
          "Automations"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations": {
      "get": {
        "summary": "Conversations, latest message first. Filter by state, kind, unread, starred, account, platform or search.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "open (default) or closed.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "dm, mention or comment.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "unread",
            "in": "query",
            "required": false,
            "description": "1 for unread only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "starred",
            "in": "query",
            "required": false,
            "description": "1 for starred only.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "description": "One connected account.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "platform",
            "in": "query",
            "required": false,
            "description": "One platform id, e.g. instagram.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Matches the username, the name or the last message.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "A lastMessageAt from the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-200.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "state": {
                    "type": "string",
                    "description": "open (default) or closed."
                  },
                  "kind": {
                    "type": "string",
                    "description": "dm, mention or comment."
                  },
                  "unread": {
                    "type": "string",
                    "description": "1 for unread only."
                  },
                  "starred": {
                    "type": "string",
                    "description": "1 for starred only."
                  },
                  "accountId": {
                    "type": "string",
                    "description": "One connected account."
                  },
                  "platform": {
                    "type": "string",
                    "description": "One platform id, e.g. instagram."
                  },
                  "search": {
                    "type": "string",
                    "description": "Matches the username, the name or the last message."
                  },
                  "before": {
                    "type": "string",
                    "description": "A lastMessageAt from the previous page."
                  },
                  "limit": {
                    "type": "string",
                    "description": "1-200."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}": {
      "get": {
        "summary": "One conversation with its contact and messages.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/messages": {
      "post": {
        "summary": "Reply as the account: a DM in DM conversations, a public reply in mention and comment conversations.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "What to send."
                  },
                  "mediaId": {
                    "type": "string",
                    "description": "Attach one uploaded file to a DM."
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/drafts/{messageId}": {
      "post": {
        "summary": "Send a draft an automation prepared for approval, optionally with edited text.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Throw a draft away without sending it.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/inbox/sync": {
      "post": {
        "summary": "Import recent conversations from the channel for one account.",
        "tags": [
          "Inbox and contacts"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/read": {
      "post": {
        "summary": "Mark it read.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/open": {
      "post": {
        "summary": "Reopen a closed conversation.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/close": {
      "post": {
        "summary": "Close it. It moves out of the open list.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/star": {
      "post": {
        "summary": "Star it.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/unstar": {
      "post": {
        "summary": "Remove the star.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/assign": {
      "post": {
        "summary": "Assign it to a person (userId, defaults to you).",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/conversations/{id}/unassign": {
      "post": {
        "summary": "Clear the assignment.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/contacts": {
      "get": {
        "summary": "People who wrote to your accounts, with tags, fields, opt-out and whether they follow you where the channel says.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "description": "One connected account.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "description": "Contacts with this tag.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "optedOut",
            "in": "query",
            "required": false,
            "description": "1 for people who opted out.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Matches the username or the name.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-500, defaults to 100.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "accountId": {
                    "type": "string",
                    "description": "One connected account."
                  },
                  "tag": {
                    "type": "string",
                    "description": "Contacts with this tag."
                  },
                  "optedOut": {
                    "type": "string",
                    "description": "1 for people who opted out."
                  },
                  "search": {
                    "type": "string",
                    "description": "Matches the username or the name."
                  },
                  "limit": {
                    "type": "string",
                    "description": "1-500, defaults to 100."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/contacts/{id}": {
      "get": {
        "summary": "One contact and their conversations.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Set tags, custom fields or opt-out.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Replaces the tags. Up to 50."
                  },
                  "fields": {
                    "type": "object",
                    "description": "Custom fields to set, merged into the existing ones."
                  },
                  "optedOut": {
                    "type": "boolean",
                    "description": "true stops every automated message to this person."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete the contact and its conversations and messages on our side. Nothing changes on the channel.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/contacts/{id}/refresh": {
      "post": {
        "summary": "Read the profile again from the channel.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/accounts/{id}/audience": {
      "get": {
        "summary": "Follower totals, and on Threads a demographic breakdown. Follower lists are not available on any channel.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/messaging/violations": {
      "get": {
        "summary": "Messages an automation did not send because a channel rule stopped it, newest first.",
        "tags": [
          "Inbox and contacts"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/threads/pending-replies": {
      "get": {
        "summary": "Replies held for approval on a Threads account.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "description": "A connected Threads account.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "accountId": {
                    "type": "string",
                    "description": "A connected Threads account."
                  }
                },
                "required": [
                  "accountId"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/threads/pending-replies/{replyId}": {
      "post": {
        "summary": "Approve or ignore one held reply.",
        "tags": [
          "Inbox and contacts"
        ],
        "parameters": [
          {
            "name": "replyId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "accountId": {
                    "type": "string",
                    "description": "The Threads account that holds the reply."
                  },
                  "approve": {
                    "type": "boolean",
                    "description": "false ignores the reply. Defaults to true."
                  }
                },
                "required": [
                  "accountId"
                ]
              }
            }
          }
        },
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/platforms": {
      "get": {
        "summary": "Every channel, its limits, and whether it is live.",
        "tags": [
          "Platforms"
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/logs": {
      "get": {
        "summary": "Recent API and agent calls, newest first, with bodies. Dashboard requests on request.",
        "tags": [
          "Errors"
        ],
        "parameters": [
          {
            "name": "requestId",
            "in": "query",
            "required": false,
            "description": "One call by the id an error response gave you.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "outcome",
            "in": "query",
            "required": false,
            "description": "failed for 4xx and 5xx, ok for the rest. Omit for everything.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Matches the path or the request id.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "YYYY-MM-DD. Calls from that day onward.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-200, defaults to 50.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "description": "A log id from a previous page's nextBefore.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "default": {
            "description": "See the error codes table in the docs.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}