{
  "openapi": "3.0.3",
  "info": {
    "title": "CuteDyno API",
    "version": "1.1.0",
    "description": "REST API for managing posts, social pages, and media in your CuteDyno workspace. Authenticate with a workspace API key (cdyn_live_*)."
  },
  "servers": [
    {
      "url": "https://api.cutedyno.com"
    }
  ],
  "tags": [
    {
      "name": "Connections",
      "description": "Connected social pages"
    },
    {
      "name": "Posts",
      "description": "Create, read, update, cancel posts"
    },
    {
      "name": "Media",
      "description": "Media upload"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Workspace API key. Create keys in the dashboard at /dashboard/api."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "SocialPage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "platform": {
            "type": "string"
          },
          "platformPageId": {
            "type": "string"
          },
          "pageName": {
            "type": "string"
          }
        }
      },
      "PublishContent": {
        "type": "object",
        "properties": {
          "contentType": {
            "type": "string",
            "enum": [
              "text",
              "image",
              "video"
            ]
          },
          "message": {
            "type": "string"
          },
          "caption": {
            "type": "string"
          },
          "link": {
            "type": "string"
          },
          "imageUrls": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "videoUrl": {
            "type": "string"
          },
          "platformCaptions": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "perAccount": {
            "type": "object"
          },
          "facebook": {
            "type": "object"
          },
          "instagram": {
            "type": "object"
          },
          "linkedin": {
            "type": "object"
          },
          "tiktok": {
            "type": "object"
          },
          "youtube": {
            "type": "object"
          },
          "threads": {
            "type": "object"
          }
        }
      },
      "Post": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "contentType": {
            "type": "string"
          },
          "caption": {
            "type": "string",
            "nullable": true
          },
          "message": {
            "type": "string",
            "nullable": true
          },
          "scheduledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "targets": {
            "type": "array"
          }
        }
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/v1/social-pages": {
      "get": {
        "operationId": "listSocialPages",
        "summary": "List Social Pages",
        "description": "Returns connected social pages for the workspace tied to your API key. Use each page id as a targetId when creating posts. Connect accounts in the dashboard first, OAuth is not available via API key.",
        "tags": [
          "Connections"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "pages": [
                    {
                      "id": "page-ext-id-123",
                      "platform": "linkedin",
                      "platformPageId": "page-ext-id-123",
                      "pageName": "My Company Page"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or expired API key"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/v1/posts": {
      "get": {
        "operationId": "listPosts",
        "summary": "List Posts",
        "description": "Returns publish jobs (posts) for the workspace tied to the API key.",
        "tags": [
          "Posts"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "posts": [
                    {
                      "id": "550e8400-e29b-41d4-a716-446655440000",
                      "state": "draft",
                      "contentType": "text",
                      "caption": "Launch day thread",
                      "message": "Launch day thread",
                      "scheduledAt": null,
                      "createdAt": "2026-06-17T10:00:00.000Z",
                      "targets": []
                    }
                  ],
                  "page": 1,
                  "limit": 20,
                  "total": 1
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or expired API key"
          },
          "500": {
            "description": "Server error"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page number"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Results per page (max 100)"
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by state: draft, scheduled, queued, published, cancelled, failed, etc."
          },
          {
            "name": "contentType",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by contentType: text, image, video"
          },
          {
            "name": "platform",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by target platform"
          }
        ]
      },
      "post": {
        "operationId": "createPost",
        "summary": "Create Post",
        "description": "Creates a draft, scheduled, or immediately queued post. Use content + targetIds (recommended) or the legacy flat body. saveAsDraft defaults to true, omitting it saves as draft (\"idea\"), not publish.",
        "tags": [
          "Posts"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "201": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "id": "550e8400-e29b-41d4-a716-446655440000",
                  "state": "draft"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or API key not tied to a user"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "402": {
            "description": "Post limit reached for billing period"
          },
          "403": {
            "description": "Workspace not found or access denied"
          },
          "404": {
            "description": "No valid pages for targetIds"
          },
          "500": {
            "description": "Server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "content": {
                  "contentType": "text",
                  "message": "Launch day thread, scheduling from my agent."
                },
                "targetIds": [
                  "page-ext-id-123"
                ],
                "saveAsDraft": true,
                "scheduledAt": "2026-06-20T09:00:00.000Z"
              }
            }
          }
        }
      }
    },
    "/v1/posts/{id}": {
      "get": {
        "operationId": "getPost",
        "summary": "Get Post",
        "description": "Returns a single post with full content, including platform options and per-account overrides.",
        "tags": [
          "Posts"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "post": {
                    "id": "550e8400-e29b-41d4-a716-446655440000",
                    "state": "draft",
                    "contentType": "text",
                    "message": "Hello world",
                    "content": {
                      "contentType": "text",
                      "message": "Hello world"
                    },
                    "targets": []
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or expired API key"
          },
          "404": {
            "description": "Post not found"
          },
          "500": {
            "description": "Server error"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Post UUID"
          }
        ]
      },
      "put": {
        "operationId": "updatePost",
        "summary": "Update Post",
        "description": "Edits a draft or scheduled post. Cannot edit published, processing, or partially published posts.",
        "tags": [
          "Posts"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "message": "Post updated",
                  "post": {
                    "id": "550e8400-e29b-41d4-a716-446655440000",
                    "state": "draft"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Cannot edit post in current state"
          },
          "401": {
            "description": "Missing, invalid, or expired API key"
          },
          "404": {
            "description": "Post not found"
          },
          "500": {
            "description": "Server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "content": {
                  "message": "Updated caption for all platforms"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Post UUID"
          }
        ]
      },
      "delete": {
        "operationId": "cancelPost",
        "summary": "Cancel Post",
        "description": "Cancels a scheduled or queued post. Sets state to cancelled.",
        "tags": [
          "Posts"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "message": "Post cancelled",
                  "id": "550e8400-e29b-41d4-a716-446655440000",
                  "state": "cancelled"
                }
              }
            }
          },
          "400": {
            "description": "Only scheduled or queued posts can be cancelled"
          },
          "401": {
            "description": "Missing, invalid, or expired API key"
          },
          "404": {
            "description": "Post not found"
          },
          "500": {
            "description": "Server error"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Post UUID"
          }
        ]
      }
    },
    "/v1/upload/signed-url": {
      "post": {
        "operationId": "signedUploadUrl",
        "summary": "Get Signed Upload URL",
        "description": "Returns a presigned S3 URL for uploading media. PUT your file to signedUrl, then use publicUrl in content.imageUrls or content.videoUrl.",
        "tags": [
          "Media"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "example": {
                  "signedUrl": "https://s3.example.com/presigned...",
                  "publicUrl": "https://cdn.cutedyno.com/workspace-xxx/images/photo.jpg",
                  "key": "workspace-xxx/images/123-photo.jpg"
                }
              }
            }
          },
          "400": {
            "description": "fileName and fileType are required"
          },
          "401": {
            "description": "Missing, invalid, or expired API key"
          },
          "500": {
            "description": "Server error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "example": {
                "fileName": "photo.jpg",
                "fileType": "image/jpeg"
              }
            }
          }
        }
      }
    }
  }
}