{
  "openapi": "3.1.0",
  "info": {
    "title": "dropspace API",
    "version": "1.0.0",
    "description": "create launches with AI-generated content, generate images and videos, manage writing personas, and publish to Twitter, Reddit, LinkedIn, Facebook, Instagram, TikTok, and more.",
    "contact": {
      "name": "dropspace",
      "url": "https://www.dropspace.dev"
    },
    "x-guidance": "dropspace lets agents schedule multi-platform social media launches. most endpoints require an API key (Authorization: Bearer ds_live_...) - create one at https://www.dropspace.dev/settings/api. POST /launches and related read endpoints additionally accept x402 wallet auth: x402 wallets get 5 free launches per month per identity, then $0.55 USDC on Base per launch. publishing is always free; only launch creation past the free tier settles. see https://www.dropspace.dev/docs#x402-payments for the full payment flow and https://api.dropspace.dev/llms.txt for product context."
  },
  "x-discovery": {
    "ownershipProofs": [
      "domain:api.dropspace.dev",
      "wellknown:https://api.dropspace.dev/.well-known/x402"
    ]
  },
  "x-service-info": {
    "categories": [
      "social",
      "marketing",
      "automation"
    ],
    "docs": {
      "homepage": "https://www.dropspace.dev",
      "apiReference": "https://www.dropspace.dev/docs",
      "llms": "https://api.dropspace.dev/llms.txt"
    }
  },
  "servers": [
    {
      "url": "https://api.dropspace.dev",
      "description": "production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "launches",
      "description": "create, manage, and publish launches across multiple platforms."
    },
    {
      "name": "personas",
      "description": "manage AI writing personas for content generation."
    },
    {
      "name": "connections",
      "description": "view your OAuth platform connections (read-only)."
    },
    {
      "name": "dropspace",
      "description": "check which official dropspace accounts are connected and available for posting."
    },
    {
      "name": "API keys",
      "description": "manage your API keys for authentication."
    },
    {
      "name": "webhooks",
      "description": "manage webhook endpoints for event notifications."
    },
    {
      "name": "usage",
      "description": "check your current plan, billing period, and usage limits."
    },
    {
      "name": "credits",
      "description": "purchase and manage credit packs for MPP (Stripe) agents. credits let agents prepay for launches in bulk, reducing per-transaction fees."
    }
  ],
  "paths": {
    "/launches": {
      "get": {
        "tags": [
          "launches"
        ],
        "summary": "list launches with pagination",
        "operationId": "listLaunches",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "agentPaymentAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success"
          },
          "402": {
            "description": "payment required — agent payment auth (x402 or MPP). launch creation beyond the free tier (5/month) costs $0.55 via x402 (crypto) or $0.60 via MPP (card).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "PAYMENT_001"
                        },
                        "message": {
                          "type": "string",
                          "example": "payment required: $0.55 USDC per launch (x402, 5 free/month) or $0.60 per launch (MPP)"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    "x402": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 2
                        },
                        "scheme": {
                          "type": "string",
                          "example": "exact"
                        },
                        "network": {
                          "type": "string",
                          "example": "eip155:8453"
                        },
                        "asset": {
                          "type": "string",
                          "example": "USDC"
                        },
                        "amount": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "receiver": {
                          "type": "string"
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    },
                    "mpp": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "stripe"
                        },
                        "intent": {
                          "type": "string",
                          "example": "charge"
                        },
                        "currency": {
                          "type": "string",
                          "example": "usd"
                        },
                        "amount_cents": {
                          "type": "integer",
                          "example": 50
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "page number",
            "schema": {
              "type": "integer",
              "default": "1"
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "description": "items per page",
            "schema": {
              "type": "string",
              "default": "50"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "filter by launch status (draft, manual, trigger, scheduled, running, completed, partial, failed, cancelled)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        }
      },
      "post": {
        "tags": [
          "launches"
        ],
        "summary": "create a launch with AI-generated or custom content",
        "operationId": "createLaunches",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "agentPaymentAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "success"
          },
          "400": {
            "description": "SERVER_002: validation error; UPLOAD_001: unsupported media type; UPLOAD_002: media file too large; UPLOAD_003: media storage upload failed; LAUNCH_007: platform requirements not met (e.g. Instagram/TikTok need media)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "payment required — agent payment auth (x402 or MPP). launch creation beyond the free tier (5/month) costs $0.55 via x402 (crypto) or $0.60 via MPP (card).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "PAYMENT_001"
                        },
                        "message": {
                          "type": "string",
                          "example": "payment required: $0.55 USDC per launch (x402, 5 free/month) or $0.60 per launch (MPP)"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    "x402": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 2
                        },
                        "scheme": {
                          "type": "string",
                          "example": "exact"
                        },
                        "network": {
                          "type": "string",
                          "example": "eip155:8453"
                        },
                        "asset": {
                          "type": "string",
                          "example": "USDC"
                        },
                        "amount": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "receiver": {
                          "type": "string"
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    },
                    "mpp": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "stripe"
                        },
                        "intent": {
                          "type": "string",
                          "example": "charge"
                        },
                        "currency": {
                          "type": "string",
                          "example": "usd"
                        },
                        "amount_cents": {
                          "type": "integer",
                          "example": 50
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_003: persona not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "LAUNCH_002: plan launch limit reached; RATE_001: content generation rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "launch title"
                  },
                  "product_description": {
                    "type": "string",
                    "description": "product description - required unless custom_content or platform_contents is provided"
                  },
                  "platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "target platforms - can be omitted when dropspace_platforms or user_platform_accounts is provided (inferred from their union)"
                  },
                  "product_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "product URL (scraped for context)"
                  },
                  "scheduled_date": {
                    "type": "string",
                    "format": "date-time",
                    "description": "schedule for future (≥ 15 min from now)"
                  },
                  "persona_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "writing style persona to use"
                  },
                  "dropspace_platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "post via dropspace official accounts"
                  },
                  "user_platform_accounts": {
                    "type": "object",
                    "description": "map of platform key → token_id (UUID). most platforms use simple keys: \"twitter\", \"reddit\", \"instagram\", \"tiktok\", \"youtube\". LinkedIn uses \"linkedin:personal\" for personal profiles or \"linkedin:organization:<org_id>\" for company pages. Facebook uses \"facebook:page:<page_id>\". multiple keys allowed (e.g. post to personal + org simultaneously)"
                  },
                  "media": {
                    "type": "array",
                    "description": "inline media upload - each item is either `{ source: \"url\", url: \"https://...\" }` to fetch from a URL, or `{ source: \"base64\", data: \"...\", filename: \"photo.jpg\", mime_type: \"image/jpeg\" }` for raw data. the server uploads to storage and populates media_assets automatically. mutually exclusive with media_assets. max 10 items (9 images + 1 video). images: jpeg, png, webp, gif (5MB). videos: mp4, mov (512MB via URL, 4MB via base64). when provided, media_attach_platforms and media_mode are auto-inferred if not set"
                  },
                  "media_assets": {
                    "type": "array",
                    "description": "pre-uploaded media objects (id, url, type, filename, size, mime_type). mutually exclusive with media"
                  },
                  "media_attach_platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "platforms to attach media to (subset of platforms). auto-inferred from selected platforms when using media"
                  },
                  "media_mode": {
                    "type": "string",
                    "enum": [
                      "images",
                      "video"
                    ],
                    "description": "media mode for the launch. auto-inferred from media types when using media"
                  },
                  "platform_contents": {
                    "type": "object",
                    "description": "pre-written content per platform - each value needs `content` (string). for Twitter, you can alternatively provide `thread` (string[], each ≤ 280 chars or ≤ 25,000 for X Premium accounts, max 6 tweets) instead of `content` - mutually exclusive with `content`. Reddit requires `title` (string, max 300 chars). Product Hunt and Hacker News support an optional `title` field (max 60 and 80 chars respectively). TikTok supports a `tiktok_settings` object with `privacy_level` (required before publishing: \"PUBLIC_TO_EVERYONE\", \"FOLLOWER_OF_CREATOR\", \"MUTUAL_FOLLOW_FRIENDS\", or \"SELF_ONLY\") and optional booleans: `allow_comments`, `allow_duet`, `allow_stitch`, `is_commercial`, `is_your_brand`, `is_branded_content`, `auto_add_music`. when provided, AI content generation is skipped. per-platform character limits are enforced: Twitter 280/tweet (25,000 for X Premium) × 6 tweets, LinkedIn 3,000, Instagram 2,200, Reddit 3,000, Facebook 3,000, TikTok 4,000, YouTube 5,000 (description, title max 100), Product Hunt 500, Hacker News 2,000, Substack 3,000. YouTube requires video and supports an optional `title` field (max 100 chars). mutually exclusive with custom_content"
                  },
                  "custom_content": {
                    "type": "string",
                    "description": "single text distributed to all selected platforms, or array of tweet strings when twitter is selected. string form is validated against the most restrictive platform limit. array form creates a twitter thread (each ≤280 chars or ≤25,000 for X Premium, max 6) and consolidates for other platforms. mutually exclusive with platform_contents. when provided, AI content generation is skipped"
                  },
                  "custom_content_reddit_title": {
                    "type": "string",
                    "description": "reddit post title - required when using custom_content with reddit in platforms"
                  },
                  "publish": {
                    "type": "boolean",
                    "description": "immediately publish after creation. returns 202 instead of 201. mutually exclusive with scheduled_date. requires both write and publish scopes (API key auth)"
                  },
                  "wait": {
                    "type": "boolean",
                    "description": "wait for publishing to complete and return post URLs inline (returns 200 with posting_status). requires publish: true. response includes posting_status with per-platform results. typical wait: 10-30s for text platforms (Twitter, LinkedIn, Reddit, Facebook), up to 60s+ with Instagram or TikTok"
                  }
                },
                "required": [
                  "title",
                  "platforms"
                ]
              }
            }
          }
        },
        "description": "the media field lets you upload images/videos inline via URL or base64 without pre-uploading to storage - the server handles upload and returns media_assets in the response\n\nmedia and media_assets are mutually exclusive - use media for inline upload, or media_assets if you've already uploaded files to storage\n\ncontent is generated automatically via Claude using your description, scraped website data, and persona style\n\ncustom_content and platform_contents are mutually exclusive - use one or the other (or neither for full AI generation)\n\nproduct_url is optional but enhances AI generation by providing scraped website data for additional context\n\nif platform_contents is provided, those platforms skip AI generation - only platforms without a truthy content field are generated\n\ncustom_content as a string distributes the same text to all platforms - validated against the lowest character limit. as an array (string[]), it creates a numbered twitter thread and joins tweets with double newlines for other platforms. array form requires twitter in platforms\n\npartial coverage is supported: provide content for some platforms and let AI generate the rest\n\nfor Twitter threads, use `platform_contents.twitter.thread: [\"tweet 1\", \"tweet 2\"]` instead of `content` - each tweet ≤ 280 chars (≤ 25,000 for X Premium accounts), max 6 tweets. mutually exclusive with `content`\n\nmedia is distributed to selected platforms with per-platform limits (Instagram/Facebook: 10, Reddit: 20, TikTok: 35)\n\nInstagram requires at least one image, video, or AI-generated video. TikTok requires video or photos\n\nTikTok requires `tiktok_settings.privacy_level` to be set before publishing (TikTok Content Sharing Guidelines). set it at creation time via `platform_contents.tiktok.tiktok_settings` or update it later via PATCH. branded content (`is_branded_content: true`) cannot use SELF_ONLY privacy\n\nwhen `publish: true`, the launch is created and immediately queued for publishing - returns **202** instead of 201. if publish validation fails after creation, returns 201 with a `publish_error` field containing `{ code, message }` - retry via `POST /launches/:id/publish`\n\n`publish` and `scheduled_date` are mutually exclusive - use one or the other\n\n`publish: true` requires at least one posting account (`user_platform_accounts` or `dropspace_platforms`). with API key auth, both `write` and `publish` scopes are required\n\n`wait: true` runs the publisher synchronously and returns 200 with `posting_status` containing per-platform results and post URLs. the request stays open until all platforms finish (typically 10-30s, up to 60s+ with Instagram/TikTok). if any platform fails, `posting_status` still shows successes - check `status` field per platform",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.550000"
          },
          "protocols": [
            {
              "x402": {}
            },
            {
              "mpp": {
                "method": "stripe",
                "intent": "charge",
                "currency": "usd"
              }
            }
          ]
        }
      }
    },
    "/launches/{id}": {
      "get": {
        "tags": [
          "launches"
        ],
        "summary": "get a single launch with posting status",
        "operationId": "getLaunche",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "agentPaymentAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success"
          },
          "402": {
            "description": "payment required — agent payment auth (x402 or MPP). launch creation beyond the free tier (5/month) costs $0.55 via x402 (crypto) or $0.60 via MPP (card).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "PAYMENT_001"
                        },
                        "message": {
                          "type": "string",
                          "example": "payment required: $0.55 USDC per launch (x402, 5 free/month) or $0.60 per launch (MPP)"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    "x402": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 2
                        },
                        "scheme": {
                          "type": "string",
                          "example": "exact"
                        },
                        "network": {
                          "type": "string",
                          "example": "eip155:8453"
                        },
                        "asset": {
                          "type": "string",
                          "example": "USDC"
                        },
                        "amount": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "receiver": {
                          "type": "string"
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    },
                    "mpp": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "stripe"
                        },
                        "intent": {
                          "type": "string",
                          "example": "charge"
                        },
                        "currency": {
                          "type": "string",
                          "example": "usd"
                        },
                        "amount_cents": {
                          "type": "integer",
                          "example": 50
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        }
      },
      "patch": {
        "tags": [
          "launches"
        ],
        "summary": "update a draft/scheduled/cancelled launch",
        "operationId": "updateLaunche",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success"
          },
          "400": {
            "description": "UPLOAD_001: unsupported media type; UPLOAD_002: media file too large; UPLOAD_003: media storage upload failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "LAUNCH_003: cannot update a running, completed, or partial launch",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "scheduled_date": {
                    "type": "string",
                    "format": "date-time",
                    "description": "schedule for future (≥ 15 min from now), null to unschedule"
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "draft",
                      "manual",
                      "trigger",
                      "scheduled",
                      "cancelled"
                    ],
                    "description": "update launch status"
                  },
                  "platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "target platforms for this launch"
                  },
                  "name": {
                    "type": "string",
                    "description": "launch name/title (max 200 chars)"
                  },
                  "product_description": {
                    "type": "string",
                    "description": "product description (max 10,000 chars)"
                  },
                  "product_url": {
                    "type": "string",
                    "description": "product URL (empty string to clear)"
                  },
                  "persona_id": {
                    "type": "string",
                    "description": "persona ID for content generation, null to clear"
                  },
                  "platform_contents": {
                    "type": "object",
                    "description": "per-platform content update (deep-merged with existing) - fields you include replace the old value, omitted fields are preserved. for Twitter, you can use `thread` (string[], each ≤ 280 chars or ≤ 25,000 for X Premium, max 6) instead of `content` - mutually exclusive with `content`. Reddit `title` is optional (existing title preserved if omitted; max 300 chars if provided). Product Hunt and Hacker News support an optional `title` field (max 60 and 80 chars respectively). TikTok `tiktok_settings` can be set or updated here (deep-merged) - see POST docs for field details. per-platform character limits are enforced: Twitter 280/tweet (25,000 for X Premium) × 6 tweets, LinkedIn 3,000, Instagram 2,200, Reddit 3,000, Facebook 3,000, TikTok 4,000, YouTube 5,000 (description, title max 100), Product Hunt 500, Hacker News 2,000, Substack 3,000. YouTube `title` is optional on update (existing title preserved if omitted)"
                  },
                  "user_platform_accounts": {
                    "type": "object",
                    "description": "map of platform key → token_id (UUID). most platforms use simple keys: \"twitter\", \"reddit\", \"instagram\", \"tiktok\", \"youtube\". LinkedIn uses \"linkedin:personal\" for personal profiles or \"linkedin:organization:<org_id>\" for company pages. Facebook uses \"facebook:page:<page_id>\". multiple keys allowed (e.g. post to personal + org simultaneously)"
                  },
                  "dropspace_platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "post via dropspace official accounts"
                  },
                  "media": {
                    "type": "array",
                    "description": "inline media upload - same format as create. replaces existing media. mutually exclusive with media_assets"
                  },
                  "media_assets": {
                    "type": "array",
                    "description": "pre-uploaded media objects. replaces existing media. mutually exclusive with media"
                  },
                  "media_attach_platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "platforms to attach media to. auto-inferred when using media"
                  },
                  "media_mode": {
                    "type": "string",
                    "enum": [
                      "images",
                      "video"
                    ],
                    "description": "media mode. auto-inferred when using media"
                  }
                }
              }
            }
          }
        },
        "description": "all fields are optional but at least one must be provided\n\na running launch can only be updated to set status to cancelled\n\nunrecognized fields return a 400 error\n\nstatus is auto-derived for editable launches (draft, manual, trigger, scheduled). the server determines status based on your launch configuration: has posting accounts (user_platform_accounts or dropspace_platforms) + scheduled_date → scheduled. has posting accounts + no scheduled_date → trigger. has content + no posting accounts → manual. you cannot force \"manual\" on a launch with posting accounts — it will auto-transition to \"trigger\". to unschedule a launch, PATCH with { \"scheduled_date\": null } — status auto-becomes \"trigger\"\n\nplatform_contents merges per platform - existing platforms not included in the update are preserved. within a platform, fields you include replace the old value\n\nfor Twitter threads, use `platform_contents.twitter.thread: [\"tweet 1\", \"tweet 2\"]` instead of `content` - each tweet ≤ 280 chars (≤ 25,000 for X Premium), max 6 tweets\n\nmedia and media_assets replace existing media entirely (no merging)\n\nTikTok `tiktok_settings` is deep-merged - you can update individual fields (e.g. only `privacy_level`) without overwriting the rest"
      },
      "delete": {
        "tags": [
          "launches"
        ],
        "summary": "delete a launch (any status except running)",
        "operationId": "deleteLaunche",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "no content"
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "LAUNCH_003: cannot delete a launch that is currently running",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ]
      }
    },
    "/launches/{id}/publish": {
      "post": {
        "tags": [
          "launches"
        ],
        "summary": "queue launch for publishing (async)",
        "operationId": "publishLaunch",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "agentPaymentAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "message": "publish queued"
                  }
                }
              }
            }
          },
          "400": {
            "description": "LAUNCH_007: platform requirements not met - see errors array for details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "payment required — agent payment auth (x402 or MPP). launch creation beyond the free tier (5/month) costs $0.55 via x402 (crypto) or $0.60 via MPP (card).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "PAYMENT_001"
                        },
                        "message": {
                          "type": "string",
                          "example": "payment required: $0.55 USDC per launch (x402, 5 free/month) or $0.60 per launch (MPP)"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    "x402": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 2
                        },
                        "scheme": {
                          "type": "string",
                          "example": "exact"
                        },
                        "network": {
                          "type": "string",
                          "example": "eip155:8453"
                        },
                        "asset": {
                          "type": "string",
                          "example": "USDC"
                        },
                        "amount": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "receiver": {
                          "type": "string"
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    },
                    "mpp": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "stripe"
                        },
                        "intent": {
                          "type": "string",
                          "example": "charge"
                        },
                        "currency": {
                          "type": "string",
                          "example": "usd"
                        },
                        "amount_cents": {
                          "type": "integer",
                          "example": 50
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "AUTH_002: plan restriction on own connected accounts (dropspace official accounts are always allowed)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "LAUNCH_004: launch is not in a publishable state or already publishing",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "LAUNCH_007: launch has no platforms configured for posting",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "description": "the launch transitions to running - poll /status or listen for launch.completed / launch.failed / post.deleted webhooks\n\nwhen validation fails (LAUNCH_007), the response includes a `details` array listing all issues that must be fixed before publishing\n\nplatform validation checks: character limits (all platforms), Reddit title ≤ 300 chars, Reddit video mode needs video (thumbnail auto-generated if not provided), Reddit image mode needs images, Instagram reel needs video, Instagram carousel needs ≥ 2 images, TikTok requires privacy_level in tiktok_settings, TikTok video mode needs video, TikTok photo mode needs images, YouTube requires video, YouTube title ≤ 100 chars, YouTube description ≤ 5,000 chars",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        }
      }
    },
    "/launches/{id}/retry": {
      "post": {
        "tags": [
          "launches"
        ],
        "summary": "retry failed platforms only",
        "operationId": "retryLaunch",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "message": "retry queued",
                    "platforms": [
                      "reddit",
                      "tiktok"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "LAUNCH_003: no failed platforms to retry",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "LAUNCH_004: launch is already running",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ]
      }
    },
    "/launches/{id}/retry-content": {
      "post": {
        "tags": [
          "launches"
        ],
        "summary": "retry content generation for failed platforms",
        "operationId": "retryContent",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "retried": [
                      "twitter",
                      "reddit"
                    ],
                    "succeeded": [
                      "twitter"
                    ],
                    "still_failing": [
                      "reddit"
                    ],
                    "rate_limited": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_002: no failed platforms to retry",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "LAUNCH_002: per-launch regeneration limit reached; RATE_001: content generation rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "filter to specific platforms"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/launches/{id}/generate-content": {
      "post": {
        "tags": [
          "launches"
        ],
        "summary": "regenerate AI content for all or specific platforms",
        "operationId": "generateContent",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "uuid",
                    "name": "announcing our new feature",
                    "platform_contents": {
                      "twitter": {
                        "content": "1/ Fresh new thread..."
                      },
                      "linkedin": {
                        "content": "New version..."
                      }
                    }
                  },
                  "generation": {
                    "platforms_generated": [
                      "linkedin",
                      "twitter"
                    ],
                    "failures": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_002: no product_description or platforms",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "LAUNCH_003: launch is running/completed/partial",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "RATE_001: content generation rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "SERVER_001: content generation unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "platforms to regenerate (defaults to all)"
                  },
                  "generate_video_scripts": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "generate video scripts for these platforms"
                  }
                }
              }
            }
          }
        },
        "description": "existing content for other platforms is preserved\n\nmedia, video sources, and generated videos are never overwritten"
      }
    },
    "/launches/{id}/status": {
      "get": {
        "tags": [
          "launches"
        ],
        "summary": "detailed posting logs per platform",
        "operationId": "getLaunchStatus",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "agentPaymentAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "launch_id": "uuid",
                    "launch_status": "completed",
                    "posting_logs": [
                      {
                        "id": "uuid",
                        "platform": "twitter",
                        "status": "success",
                        "post_url": "https://x.com/...",
                        "post_id": "string | null",
                        "error_message": "string | null",
                        "error_code": "string | null",
                        "attempt_count": 1,
                        "posted_at": "ISO 8601",
                        "created_at": "ISO 8601"
                      }
                    ]
                  }
                }
              }
            }
          },
          "402": {
            "description": "payment required — agent payment auth (x402 or MPP). launch creation beyond the free tier (5/month) costs $0.55 via x402 (crypto) or $0.60 via MPP (card).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "PAYMENT_001"
                        },
                        "message": {
                          "type": "string",
                          "example": "payment required: $0.55 USDC per launch (x402, 5 free/month) or $0.60 per launch (MPP)"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    "x402": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 2
                        },
                        "scheme": {
                          "type": "string",
                          "example": "exact"
                        },
                        "network": {
                          "type": "string",
                          "example": "eip155:8453"
                        },
                        "asset": {
                          "type": "string",
                          "example": "USDC"
                        },
                        "amount": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "receiver": {
                          "type": "string"
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    },
                    "mpp": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "stripe"
                        },
                        "intent": {
                          "type": "string",
                          "example": "charge"
                        },
                        "currency": {
                          "type": "string",
                          "example": "usd"
                        },
                        "amount_cents": {
                          "type": "integer",
                          "example": 50
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        }
      }
    },
    "/launches/{id}/analytics": {
      "get": {
        "tags": [
          "launches"
        ],
        "summary": "publishing analytics with per-post engagement metrics (live refresh)",
        "operationId": "getLaunchAnalytics",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "launch_id": "uuid",
                    "launch_name": "announcing our new feature",
                    "launch_status": "completed",
                    "summary": {
                      "total": 3,
                      "successful": 3,
                      "failed": 0,
                      "pending": 0
                    },
                    "fetched_at": "2026-02-22T10:00:00Z",
                    "next_refresh_at": "2026-02-22T10:05:00Z",
                    "platforms": [
                      {
                        "platform": "twitter",
                        "status": "success",
                        "post_url": "https://x.com/...",
                        "post_id": "1234567890",
                        "posted_at": "ISO 8601",
                        "cache_status": "refreshed",
                        "is_deleted": false,
                        "deleted_detected_at": null,
                        "deletion_reason": null,
                        "metrics": {
                          "likes": 42,
                          "retweets": 12,
                          "replies": 5,
                          "quotes": 2,
                          "bookmarks": 8,
                          "impressions": 1500,
                          "urlClicks": 23,
                          "profileClicks": 7,
                          "fetched_at": "2026-02-22T10:00:00Z"
                        }
                      },
                      {
                        "platform": "reddit",
                        "status": "success",
                        "post_url": "https://reddit.com/...",
                        "post_id": "abc123",
                        "posted_at": "ISO 8601",
                        "cache_status": "fresh",
                        "is_deleted": false,
                        "deleted_detected_at": null,
                        "deletion_reason": null,
                        "metrics": {
                          "score": 156,
                          "upvotes": 200,
                          "upvoteRatio": 0.78,
                          "comments": 34,
                          "fetched_at": "2026-02-22T09:58:00Z"
                        }
                      }
                    ]
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "description": "metrics are fetched live from platform APIs when stale (older than 5 minutes). calling this endpoint triggers a refresh automatically.\n\nfetched_at is the most recent timestamp when metrics were collected. next_refresh_at indicates when calling again could yield fresh data (fetched_at + 5 min).\n\ncache_status per platform: fresh (< 5 min old, from cache), refreshed (fetched from platform API), stale (rate limited or no token, returning older data), unavailable (no data exists). omitted for non-success posts (failed, pending).\n\nrate-limited platforms return stale cached data instead of failing - the response always includes the best available metrics.\n\nmetric fields vary by platform: Twitter (likes, retweets, replies, quotes, bookmarks, impressions, urlClicks, profileClicks), LinkedIn (impressions, uniqueImpressions, likes, comments, shares, clicks, engagement), Facebook (reactions, comments, shares), Instagram (views, engagement, saved, likes, comments, shares), Reddit (score, upvotes, upvoteRatio, comments), TikTok (views, likes, comments, shares)\n\nis_deleted indicates whether the post was detected as removed from the platform. when true, deleted_detected_at contains the detection timestamp and deletion_reason contains the reason. possible values: not_found (post no longer exists), gone (permanently removed, HTTP 410), creator_deleted (deleted by creator), moderation_removed (removed by moderation), account_deleted (account was deleted), spam_filtered (caught by spam filter). deletion is detected during metrics refresh."
      }
    },
    "/launches/analytics": {
      "get": {
        "tags": [
          "launches"
        ],
        "summary": "batch analytics for multiple launches (cache-only, no live refresh)",
        "operationId": "getBatchLaunchAnalytics",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "launch_id": "uuid",
                      "launch_name": "announcing our new feature",
                      "launch_status": "completed",
                      "summary": {
                        "total": 3,
                        "successful": 2,
                        "failed": 1,
                        "pending": 0
                      },
                      "platforms": [
                        {
                          "platform": "twitter",
                          "status": "success",
                          "post_url": "https://x.com/...",
                          "post_id": "1234567890",
                          "posted_at": "ISO 8601",
                          "is_deleted": false,
                          "deleted_detected_at": null,
                          "deletion_reason": null,
                          "cache_status": "fresh",
                          "metrics": {
                            "likes": 42,
                            "retweets": 12,
                            "impressions": 1500,
                            "fetched_at": "2026-02-22T10:00:00Z"
                          }
                        }
                      ]
                    }
                  ],
                  "errors": [
                    {
                      "id": "invalid-uuid",
                      "error": {
                        "code": "LAUNCH_001",
                        "message": "launch not found"
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "SERVER_002: ids parameter missing or empty; SERVER_002: more than 100 IDs provided; SERVER_005: all IDs have invalid UUID format",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "ids",
            "in": "query",
            "required": true,
            "description": "comma-separated launch UUIDs (max 100)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "returns cached analytics only - does NOT trigger a live refresh from platform APIs. use the single-launch endpoint GET /launches/:id/analytics to trigger a fresh fetch.\n\naccepts up to 100 launch IDs. duplicate IDs are deduplicated. counts as 1 rate limit hit.\n\nresponse includes partial results: valid launches in data[], invalid/not-found in errors[].\n\ncache_status per platform: fresh (< 5 min old), stale (older cached data), unavailable (no metrics exist). never returns refreshed (no live fetch). omitted for non-success posts (failed, pending).\n\nmetric fields vary by platform - same as single-launch analytics endpoint."
      }
    },
    "/launches/{id}/posts/{logId}": {
      "delete": {
        "tags": [
          "launches"
        ],
        "summary": "delete a single published post from its platform",
        "operationId": "deletePost",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "DELETE_NOT_SUPPORTED: platform does not support API deletion (Instagram, TikTok) - returned in response body, not as HTTP error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found; SERVER_003: posting log not found or not deletable",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          },
          {
            "name": "logId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "logId"
          }
        ],
        "description": "requires 'delete' scope on your API key (not included by default - add it in API key settings)\n\nonly works for Twitter, Facebook, LinkedIn, and Reddit - Instagram and TikTok do not support API deletion\n\nthe posting log must have status 'success' and a valid post_id\n\nif the post was already deleted on the platform (404), it is treated as a successful deletion\n\non success, the posting log status is updated to 'deleted'\n\nlogId is the posting_log UUID from the /status endpoint"
      }
    },
    "/launches/{id}/posts": {
      "delete": {
        "tags": [
          "launches"
        ],
        "summary": "delete all published posts for a launch from their platforms",
        "operationId": "deletePost",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "results": [
                      {
                        "success": true,
                        "platform": "twitter",
                        "post_id": "123",
                        "deleted_at": "ISO 8601"
                      },
                      {
                        "success": true,
                        "platform": "linkedin",
                        "post_id": "urn:li:share:456",
                        "deleted_at": "ISO 8601"
                      },
                      {
                        "success": false,
                        "platform": "instagram",
                        "post_id": "789",
                        "error": "platform does not support deletion",
                        "error_code": "DELETE_NOT_SUPPORTED"
                      }
                    ],
                    "no_failures": false,
                    "deleted_count": 2,
                    "failed_count": 0,
                    "skipped_count": 1
                  }
                }
              }
            }
          },
          "404": {
            "description": "LAUNCH_001: launch not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "description": "requires 'delete' scope on your API key (not included by default - add it in API key settings)\n\nonly deletes from Twitter, Facebook, LinkedIn, and Reddit\n\nInstagram and TikTok posts are skipped with DELETE_NOT_SUPPORTED (require manual deletion)\n\nreturns detailed results per post including success/failure status\n\nskipped_count includes platforms that don't support API deletion"
      }
    },
    "/personas": {
      "get": {
        "tags": [
          "personas"
        ],
        "summary": "list personas with pagination",
        "operationId": "listPersonas",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "uuid",
                      "name": "string",
                      "persona_analysis": "object | null",
                      "build_status": "idle|building|complete|error",
                      "build_progress": 0,
                      "build_started_at": "ISO 8601 | null",
                      "build_error": "string | null",
                      "last_analyzed_at": "ISO 8601 | null",
                      "created_at": "ISO 8601",
                      "updated_at": "ISO 8601"
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "page_size": 50,
                    "total": 3,
                    "total_pages": 1
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "page number",
            "schema": {
              "type": "integer",
              "default": "1"
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "description": "items per page",
            "schema": {
              "type": "string",
              "default": "50"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "personas"
        ],
        "summary": "create a new persona",
        "operationId": "createPersonas",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "success"
          },
          "409": {
            "description": "SERVER_009: duplicate persona name",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "PERSONA_001: persona creation limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "persona name"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/personas/{id}": {
      "get": {
        "tags": [
          "personas"
        ],
        "summary": "get persona with all writing samples",
        "operationId": "getPersona",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success"
          },
          "404": {
            "description": "PERSONA_002: persona not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "description": "includes persona_analysis, persona_analysis_structured, custom_samples, twitter_samples, reddit_samples, facebook_samples, instagram_samples, tiktok_samples, linkedin_samples, youtube_samples"
      },
      "patch": {
        "tags": [
          "personas"
        ],
        "summary": "update name and/or writing samples",
        "operationId": "updatePersona",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success"
          },
          "404": {
            "description": "PERSONA_002: persona not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "SERVER_009: duplicate persona name",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "persona name"
                  },
                  "custom_samples": {
                    "type": "string",
                    "description": "custom writing samples"
                  },
                  "twitter_samples": {
                    "type": "string",
                    "description": "Twitter writing samples"
                  },
                  "reddit_samples": {
                    "type": "string",
                    "description": "Reddit writing samples"
                  },
                  "facebook_samples": {
                    "type": "string",
                    "description": "Facebook writing samples"
                  },
                  "instagram_samples": {
                    "type": "string",
                    "description": "Instagram writing samples"
                  },
                  "tiktok_samples": {
                    "type": "string",
                    "description": "TikTok writing samples"
                  },
                  "linkedin_samples": {
                    "type": "string",
                    "description": "LinkedIn writing samples"
                  },
                  "youtube_samples": {
                    "type": "string",
                    "description": "YouTube writing samples"
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "personas"
        ],
        "summary": "delete a persona",
        "operationId": "deletePersona",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "no content"
          },
          "404": {
            "description": "PERSONA_002: persona not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "SERVER_005: persona in use by launches",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "description": "cannot delete if used by any launches"
      }
    },
    "/personas/{id}/analyze": {
      "post": {
        "tags": [
          "personas"
        ],
        "summary": "trigger AI persona analysis (async)",
        "operationId": "analyzePersona",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "202": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "started": true,
                    "persona_id": "uuid"
                  }
                }
              }
            }
          },
          "404": {
            "description": "PERSONA_002: persona not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "SERVER_009: already building",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "PERSONA_003: persona build limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "platforms": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "which platforms to analyze"
                  },
                  "include_custom_samples": {
                    "type": "boolean",
                    "description": "include custom samples in analysis",
                    "default": "false"
                  }
                }
              }
            }
          }
        },
        "description": "listen for persona.analyzed webhook when complete"
      }
    },
    "/connections": {
      "get": {
        "tags": [
          "connections"
        ],
        "summary": "list your OAuth platform connections",
        "operationId": "listConnections",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "uuid",
                      "platform": "twitter",
                      "entity_id": "string",
                      "account_info": {
                        "username": "...",
                        "display_name": "..."
                      },
                      "account_type": "personal",
                      "is_active": true,
                      "expires_at": "ISO 8601 | null",
                      "created_at": "ISO 8601",
                      "updated_at": "ISO 8601"
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "page_size": 50,
                    "total": 5,
                    "total_pages": 1
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "page number",
            "schema": {
              "type": "integer",
              "default": "1"
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "description": "items per page",
            "schema": {
              "type": "string",
              "default": "50"
            }
          }
        ],
        "description": "connections are managed via the dashboard OAuth flow - this endpoint is read-only"
      }
    },
    "/dropspace/status": {
      "get": {
        "tags": [
          "dropspace"
        ],
        "summary": "check which official dropspace accounts are connected",
        "operationId": "getLaunchStatus",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "platforms": [
                      {
                        "platform": "facebook",
                        "connected": true,
                        "account_name": "dropspace"
                      },
                      {
                        "platform": "linkedin",
                        "connected": true,
                        "account_name": "dropspace"
                      },
                      {
                        "platform": "twitter",
                        "connected": true,
                        "account_name": "@dropspace"
                      },
                      {
                        "platform": "reddit",
                        "connected": false
                      },
                      {
                        "platform": "instagram",
                        "connected": true,
                        "account_name": "@dropspace"
                      },
                      {
                        "platform": "tiktok",
                        "connected": false
                      },
                      {
                        "platform": "youtube",
                        "connected": false
                      }
                    ],
                    "connected_platforms": [
                      "facebook",
                      "linkedin",
                      "twitter",
                      "instagram"
                    ],
                    "timestamp": "ISO 8601"
                  }
                }
              }
            }
          }
        },
        "description": "always returns all 7 auto-post platforms in canonical order\n\naccount_name is only present when connected and account info exists\n\nconnected_platforms lists valid values for the dropspace_platforms field when creating launches\n\nchecks is_active flag and token expiry from the database - does not perform live health checks"
      }
    },
    "/keys/me": {
      "get": {
        "tags": [
          "API keys"
        ],
        "summary": "get the current API key's info",
        "operationId": "listMe",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "uuid",
                    "name": "my integration",
                    "key_prefix": "ds_live_abc...",
                    "scopes": [
                      "read",
                      "write",
                      "publish",
                      "generate"
                    ],
                    "created_at": "ISO 8601"
                  }
                }
              }
            }
          }
        },
        "description": "no scope required - any valid API key can check its own permissions"
      }
    },
    "/keys": {
      "get": {
        "tags": [
          "API keys"
        ],
        "summary": "list all API keys",
        "operationId": "listKeys",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "uuid",
                      "name": "my integration",
                      "key_prefix": "ds_live_abc...",
                      "scopes": [
                        "read",
                        "write",
                        "publish",
                        "generate"
                      ],
                      "last_used_at": "ISO 8601 | null",
                      "revoked_at": "ISO 8601 | null",
                      "created_at": "ISO 8601"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "API keys"
        ],
        "summary": "create a new API key (max 10)",
        "operationId": "createKeys",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "key": "ds_live_abc123...",
                    "api_key": {
                      "id": "uuid",
                      "name": "my integration",
                      "key_prefix": "ds_live_abc...",
                      "scopes": [
                        "read",
                        "write",
                        "publish",
                        "generate"
                      ],
                      "created_at": "ISO 8601"
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "key name"
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "permission scopes (default: read, write, publish, generate). available: read, write, delete, publish, generate, admin"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "description": "the full key is shown only once - store it securely"
      }
    },
    "/keys/{id}": {
      "patch": {
        "tags": [
          "API keys"
        ],
        "summary": "rename an API key",
        "operationId": "updateKey",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "uuid",
                    "name": "renamed key",
                    "key_prefix": "ds_live_abc...",
                    "last_used_at": "ISO 8601 | null",
                    "revoked_at": "ISO 8601 | null",
                    "created_at": "ISO 8601"
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_003: api key not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "SERVER_009: an api key with this name already exists",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "new key name"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "API keys"
        ],
        "summary": "revoke an API key",
        "operationId": "deleteKey",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "no content"
          },
          "404": {
            "description": "SERVER_003: api key not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ]
      }
    },
    "/webhooks": {
      "get": {
        "tags": [
          "webhooks"
        ],
        "summary": "list webhook endpoints",
        "operationId": "listWebhooks",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "uuid",
                      "url": "https://your-app.com/webhooks",
                      "events": [
                        "launch.completed",
                        "launch.failed",
                        "post.deleted"
                      ],
                      "active": true,
                      "created_at": "ISO 8601",
                      "updated_at": "ISO 8601"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "create a webhook endpoint (max 10)",
        "operationId": "createWebhooks",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "uuid",
                    "url": "https://your-app.com/webhooks",
                    "events": [
                      "launch.completed",
                      "launch.failed",
                      "post.deleted"
                    ],
                    "secret": "a1b2c3d4...",
                    "active": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_002: invalid webhook url or events; SERVER_002: maximum 10 webhook endpoints allowed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "webhook delivery URL"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "event types to subscribe to"
                  }
                },
                "required": [
                  "url",
                  "events"
                ]
              }
            }
          }
        },
        "description": "the secret is shown only once - store it securely for signature verification\n\navailable events: \"launch.completed\" (launch finished publishing), \"launch.failed\" (launch failed to publish), \"launch.partial\" (launch partially succeeded), \"media.ready\" (media generation completed), \"persona.analyzed\" (persona analysis completed), \"post.deleted\" (a published post was detected as deleted from its platform)\n\npost.deleted payload: { \"event\": \"post.deleted\", \"data\": { \"launch_id\": \"uuid\", \"platform\": \"twitter\", \"post_url\": \"https://...\", \"post_id\": \"12345\", \"deletion_reason\": \"not_found\", \"detected_at\": \"2025-01-15T10:30:00Z\" } }\n\ndeletion_reason values: not_found, gone, creator_deleted, moderation_removed, account_deleted, spam_filtered"
      }
    },
    "/webhooks/{id}": {
      "get": {
        "tags": [
          "webhooks"
        ],
        "summary": "get a webhook endpoint",
        "operationId": "getWebhook",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "uuid",
                    "url": "https://your-app.com/webhooks",
                    "events": [
                      "launch.completed",
                      "launch.failed",
                      "post.deleted"
                    ],
                    "active": true,
                    "created_at": "ISO 8601",
                    "updated_at": "ISO 8601"
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_003: webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ]
      },
      "patch": {
        "tags": [
          "webhooks"
        ],
        "summary": "update url, events, or active status",
        "operationId": "updateWebhook",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success"
          },
          "400": {
            "description": "SERVER_002: invalid webhook url or events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_003: webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "new webhook URL"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "new event subscriptions"
                  },
                  "active": {
                    "type": "boolean",
                    "description": "enable/disable endpoint"
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "webhooks"
        ],
        "summary": "delete a webhook endpoint",
        "operationId": "deleteWebhook",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "no content"
          },
          "404": {
            "description": "SERVER_003: webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ]
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "post": {
        "tags": [
          "webhooks"
        ],
        "summary": "rotate the signing secret (new secret shown once)",
        "operationId": "rotateWebhookSecret",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": "uuid",
                    "secret": "a1b2c3d4..."
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_003: webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          }
        ],
        "description": "the new secret is shown only once - update your verification code immediately\n\nthe old secret becomes invalid immediately after rotation\n\nin-flight webhook deliveries (already queued) use the secret from enqueue time and are not affected"
      }
    },
    "/webhooks/{id}/deliveries": {
      "get": {
        "tags": [
          "webhooks"
        ],
        "summary": "list delivery attempts with pagination",
        "operationId": "getWebhookDeliveries",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "uuid",
                      "event_type": "launch.completed",
                      "status": "delivered|pending|failed",
                      "attempts": 1,
                      "response_status": 200,
                      "delivered_at": "ISO 8601",
                      "created_at": "ISO 8601"
                    }
                  ],
                  "pagination": {
                    "page": 1,
                    "page_size": 50,
                    "total": 12,
                    "total_pages": 1
                  }
                }
              }
            }
          },
          "404": {
            "description": "SERVER_003: webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "id"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "page number",
            "schema": {
              "type": "integer",
              "default": "1"
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "description": "items per page",
            "schema": {
              "type": "string",
              "default": "50"
            }
          }
        ]
      }
    },
    "/usage": {
      "get": {
        "tags": [
          "usage"
        ],
        "summary": "get plan limits and current usage",
        "operationId": "listUsage",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "agentPaymentAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "plan": "starter",
                    "billing_period": {
                      "start": "ISO 8601",
                      "end": "ISO 8601"
                    },
                    "limits": {
                      "launches_per_month": {
                        "limit": 50,
                        "used": 3,
                        "remaining": 47
                      },
                      "ai_images_per_month": {
                        "limit": 100,
                        "used": 12,
                        "remaining": 88
                      },
                      "ai_videos_per_month": {
                        "limit": 20,
                        "used": 5,
                        "remaining": 15
                      },
                      "personas": {
                        "limit": 10,
                        "used": 2,
                        "remaining": 8
                      },
                      "analyses_per_persona": {
                        "limit": 3
                      },
                      "regenerations_per_launch": {
                        "limit": 5
                      }
                    },
                    "features": {
                      "can_connect_own_accounts": true,
                      "can_post_to_official_accounts": true,
                      "allowed_platforms": [
                        "facebook",
                        "linkedin",
                        "twitter",
                        "reddit",
                        "instagram",
                        "tiktok",
                        "youtube"
                      ]
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "payment required — agent payment auth (x402 or MPP). launch creation beyond the free tier (5/month) costs $0.55 via x402 (crypto) or $0.60 via MPP (card).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "PAYMENT_001"
                        },
                        "message": {
                          "type": "string",
                          "example": "payment required: $0.55 USDC per launch (x402, 5 free/month) or $0.60 per launch (MPP)"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    "x402": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 2
                        },
                        "scheme": {
                          "type": "string",
                          "example": "exact"
                        },
                        "network": {
                          "type": "string",
                          "example": "eip155:8453"
                        },
                        "asset": {
                          "type": "string",
                          "example": "USDC"
                        },
                        "amount": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "receiver": {
                          "type": "string"
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    },
                    "mpp": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "stripe"
                        },
                        "intent": {
                          "type": "string",
                          "example": "charge"
                        },
                        "currency": {
                          "type": "string",
                          "example": "usd"
                        },
                        "amount_cents": {
                          "type": "integer",
                          "example": 50
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "description": "limit and remaining can be \"unlimited\" (string) instead of a number for higher-tier plans\n\npersonas is a lifetime limit (not per billing period)\n\nanalyses_per_persona and regenerations_per_launch are per-resource limits (no used/remaining tracking)",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        },
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "description": "API key (Bearer ds_live_...) or x402 payment header (PAYMENT-SIGNATURE/X-PAYMENT, base64 challenge response).",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/credits": {
      "get": {
        "tags": [
          "credits"
        ],
        "summary": "get credit balance and available packs",
        "operationId": "listCredits",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "agentPaymentAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "balance": 7,
                    "packs": [
                      {
                        "id": "pack_20",
                        "credits": 20,
                        "price_usd": "12.00"
                      }
                    ],
                    "purchase_endpoint": "POST /credits/purchase"
                  }
                }
              }
            }
          },
          "402": {
            "description": "payment required — agent payment auth (x402 or MPP). launch creation beyond the free tier (5/month) costs $0.55 via x402 (crypto) or $0.60 via MPP (card).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "PAYMENT_001"
                        },
                        "message": {
                          "type": "string",
                          "example": "payment required: $0.55 USDC per launch (x402, 5 free/month) or $0.60 per launch (MPP)"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    "x402": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 2
                        },
                        "scheme": {
                          "type": "string",
                          "example": "exact"
                        },
                        "network": {
                          "type": "string",
                          "example": "eip155:8453"
                        },
                        "asset": {
                          "type": "string",
                          "example": "USDC"
                        },
                        "amount": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "receiver": {
                          "type": "string"
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    },
                    "mpp": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "stripe"
                        },
                        "intent": {
                          "type": "string",
                          "example": "charge"
                        },
                        "currency": {
                          "type": "string",
                          "example": "usd"
                        },
                        "amount_cents": {
                          "type": "integer",
                          "example": 50
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "description": "returns balance 0 for x402 wallets and API key users (credits are MPP-only)\n\nbalance is cached in Redis (5-min TTL) with database as source of truth",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        },
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "description": "API key (Bearer ds_live_...) or x402 payment header (PAYMENT-SIGNATURE/X-PAYMENT, base64 challenge response).",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/credits/purchase": {
      "post": {
        "tags": [
          "credits"
        ],
        "summary": "purchase a credit pack via MPP payment",
        "operationId": "createPurchase",
        "security": [
          {
            "bearerAuth": []
          },
          {
            "agentPaymentAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "credits_added": 20,
                    "new_balance": 27,
                    "pack": {
                      "id": "pack_20",
                      "credits": 20,
                      "price_usd": "12.00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "SERVER_002: x402 wallets cannot purchase credits (MPP only)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "payment required — agent payment auth (x402 or MPP). launch creation beyond the free tier (5/month) costs $0.55 via x402 (crypto) or $0.60 via MPP (card).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "PAYMENT_001"
                        },
                        "message": {
                          "type": "string",
                          "example": "payment required: $0.55 USDC per launch (x402, 5 free/month) or $0.60 per launch (MPP)"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    "x402": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 2
                        },
                        "scheme": {
                          "type": "string",
                          "example": "exact"
                        },
                        "network": {
                          "type": "string",
                          "example": "eip155:8453"
                        },
                        "asset": {
                          "type": "string",
                          "example": "USDC"
                        },
                        "amount": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "receiver": {
                          "type": "string"
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    },
                    "mpp": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "integer",
                          "example": 1
                        },
                        "method": {
                          "type": "string",
                          "example": "stripe"
                        },
                        "intent": {
                          "type": "string",
                          "example": "charge"
                        },
                        "currency": {
                          "type": "string",
                          "example": "usd"
                        },
                        "amount_cents": {
                          "type": "integer",
                          "example": 50
                        },
                        "resource": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "PAYMENT_004: payment processed but credits could not be added (contact support)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "pack": {
                    "type": "string",
                    "description": "credit pack ID to purchase (default: \"pack_20\")",
                    "default": "\"pack_20\""
                  }
                }
              }
            }
          }
        },
        "description": "MPP agents only - x402 wallets are rejected with 400 (crypto has low fees already)\n\nthe MPP credential must be for the pack price ($12.00 = 1200 cents), not the per-launch price\n\ncredits never expire and are deducted automatically when creating launches\n\nif a launch creation fails after credit deduction, the credit is refunded automatically\n\nduplicate purchases with the same MPP credential are rejected (idempotent)",
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key starting with ds_live_. Create at https://www.dropspace.dev/settings under API keys."
      },
      "agentPaymentAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-PAYMENT",
        "description": "agent payment auth. supports x402 (X-PAYMENT header with base64-encoded payment proof) and MPP (Authorization: Payment header with Stripe credential). x402 wallets get 5 free launches/month; beyond that, launch creation costs $0.55 via x402 (crypto) or $0.60 via MPP (card). see https://www.x402.org for x402 details."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "example": "LAUNCH_001"
              },
              "message": {
                "type": "string",
                "example": "launch not found"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        }
      }
    }
  }
}