{
  "openapi": "3.1.0",
  "info": {
    "title": "Posto API",
    "version": "1.0.0",
    "description": "API publik Posto (paket Agency atau add-on \"API & MCP\"). Semua respons `{ok, data, meta?}` atau `{ok:false, error:{code, message, reason?, fix?, details?}}` (`reason` = kode mesin UPPER_SNAKE, `fix` = langkah perbaikan), header `X-Request-Id` di setiap respons.\n\n- **Auth**: `Authorization: Bearer pk_live_…` (buat di Pengaturan → API). Scope key: `read`, `create`, `schedule`.\n- **Batas**: 60 request/menit per key, 10 generate bersamaan per key (header `X-RateLimit-*`, `Retry-After`).\n- **Credit AI**: sama dengan web — hanya aksi AI yang memakai Credit AI (tarif per aksi diatur admin; ekspor, jadwal, posting, dan Reels non-AI 0), dipotong sebelum AI, dikembalikan otomatis bila gagal.\n- **Idempotency-Key** wajib di POST /carousels, /carousels/{id}/images, /batches (body beda → 409); opsional (disarankan) di POST /schedules, /schedule-series, /carousels/{id}/video-exports.\n- **Reels & jadwal berulang**: `format: \"reels\"` di POST /schedules & /schedule-series, video MP4 lewat POST /carousels/{id}/video-exports (paket Pro, Ultimate, dan Agency).\n- **Video & media**: GET /videos (sementara 24 jam + tersimpan), POST /videos/{id}/save (simpan permanen, kuota penyimpanan), GET /media (gambar AI & unggahan), DELETE untuk keduanya.\n- **Agency**: header `X-Workspace-Id` (atau `brandId`) ke workspace klien dari GET /brands.\n- **Akun & error mesin**: GET /accounts (akun sosial brand), GET /accounts/{id}/tiktok-creator-info. Error jalur jadwal memuat `error.reason` + `error.fix` + `details.issues[]` (semua masalah sekaligus).\n- **Webhook**: daftarkan endpoint di POST /webhooks; verifikasi `X-Posto-Signature` (HMAC-SHA256 atas `{timestamp}.{raw body}`, toleransi 300 detik). Event & payload: bagian Webhooks.\n- **ID**: uuid mentah. Klien wajib mengabaikan field yang tidak dikenal.",
    "contact": {
      "name": "Posto",
      "url": "https://posto.id/help"
    }
  },
  "servers": [
    {
      "url": "https://posto.id/api/v1",
      "description": "Produksi"
    },
    {
      "url": "https://staging.posto.id/api/v1",
      "description": "Staging (key pk_test_…)"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Carousels"
    },
    {
      "name": "Export"
    },
    {
      "name": "Schedules"
    },
    {
      "name": "Series",
      "description": "Jadwal berulang: posting ulang carousel yang sama menurut aturan"
    },
    {
      "name": "Brands"
    },
    {
      "name": "Accounts",
      "description": "Akun sosial terhubung per brand & info kreator TikTok"
    },
    {
      "name": "Templates"
    },
    {
      "name": "Ideas"
    },
    {
      "name": "Credits"
    },
    {
      "name": "Batches"
    },
    {
      "name": "Webhooks"
    },
    {
      "name": "Videos",
      "description": "Video Reels workspace: sementara 24 jam & simpan permanen"
    },
    {
      "name": "Media",
      "description": "Gambar AI & unggahan workspace"
    },
    {
      "name": "Uploads",
      "description": "Unggah foto/video sendiri untuk posting media sendiri (URL bertanda tangan)"
    }
  ],
  "paths": {
    "/carousels": {
      "post": {
        "operationId": "createCarousel",
        "tags": [
          "Carousels"
        ],
        "summary": "Buat carousel",
        "description": "Generate async dari link, teks, ide (`id` dari GET /ideas), atau foto produk. Memakai Credit AI dengan tarif yang diatur admin: umumnya 1 per slide, ditambah Credit AI per gambar AI bila `images: true` (flyer penutup brand 0); total ada di `credits` respons. Dipotong sebelum AI dan dikembalikan otomatis bila gagal. Pantau dengan GET /carousels/{id} (polling 3 detik). Maksimal 10 generate berjalan bersamaan per key.\n\nScope: `create` · Credit AI: per slide + per gambar AI (tarif admin) · `Idempotency-Key` wajib",
        "x-scope": "create",
        "x-credits": "per slide + per gambar AI (tarif admin)",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/carousels \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Idempotency-Key: order-8812\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"source\":{\"type\":\"link\",\"value\":\"https://contoh.id/artikel/pricing-kopi\"},\"slides\":5,\"ratio\":\"4:5\",\"lang\":\"id\",\"tone\":\"santai\",\"images\":true}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'order-8812' },\n  body: JSON.stringify({\"source\":{\"type\":\"link\",\"value\":\"https://contoh.id/artikel/pricing-kopi\"},\"slides\":5,\"ratio\":\"4:5\",\"lang\":\"id\",\"tone\":\"santai\",\"images\":true}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Buat carousel\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/carousels\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendHeaders\": true,\n        \"headerParameters\": {\n          \"parameters\": [\n            {\n              \"name\": \"Idempotency-Key\",\n              \"value\": \"={{ $json.id }}\"\n            }\n          ]\n        },\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"source\\\":{\\\"type\\\":\\\"link\\\",\\\"value\\\":\\\"https://contoh.id/artikel/pricing-kopi\\\"},\\\"slides\\\":5,\\\"ratio\\\":\\\"4:5\\\",\\\"lang\\\":\\\"id\\\",\\\"tone\\\":\\\"santai\\\",\\\"images\\\":true}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 128,
              "description": "Wajib. Kunci unik per permintaan (≤ 128 karakter ASCII), disimpan 24 jam."
            },
            "required": true,
            "description": "Wajib. Kunci unik per permintaan (≤ 128 karakter ASCII), disimpan 24 jam."
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "source": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "link",
                          "text",
                          "idea",
                          "product"
                        ]
                      },
                      "value": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 20000,
                        "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                      }
                    },
                    "required": [
                      "type",
                      "value"
                    ]
                  },
                  "slides": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 12
                  },
                  "ratio": {
                    "type": "string",
                    "enum": [
                      "4:5",
                      "1:1",
                      "9:16"
                    ]
                  },
                  "lang": {
                    "type": "string",
                    "enum": [
                      "id",
                      "en",
                      "ms"
                    ]
                  },
                  "tone": {
                    "type": "string",
                    "enum": [
                      "santai",
                      "profesional",
                      "edukatif",
                      "storytelling",
                      "jualan",
                      "lucu"
                    ]
                  },
                  "templateId": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                  },
                  "templateFamily": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                  },
                  "images": {
                    "description": "Foto AI per slide (memakai Credit AI per gambar sesuai tarif admin). Tidak dikirim = otomatis: nyala bila Credit AI & batas harian cukup, selain itu mati.",
                    "type": "boolean"
                  },
                  "imageTier": {
                    "type": "string",
                    "enum": [
                      "standard",
                      "high"
                    ]
                  },
                  "visualMode": {
                    "default": "auto",
                    "type": "string",
                    "enum": [
                      "auto",
                      "photo",
                      "illustration",
                      "icon",
                      "type"
                    ]
                  },
                  "imageStyle": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                  },
                  "imageStyleCustom": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 120,
                    "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                  },
                  "imageTheme": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                  },
                  "imageSource": {
                    "default": "ai",
                    "type": "string",
                    "enum": [
                      "ai",
                      "product",
                      "source"
                    ]
                  },
                  "productMediaId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "productBackground": {
                    "type": "string",
                    "enum": [
                      "ai",
                      "original"
                    ]
                  },
                  "contentFormat": {
                    "description": "Format konten (news, explainer, data, how_to, listicle, myth_fact, comparison, promo, catalog, testimonial, story, opinion, event, general). Kosong = dideteksi otomatis dari materi; general = struktur hook → poin → penutup. Tidak mengubah Credit AI.",
                    "type": "string",
                    "enum": [
                      "general",
                      "news",
                      "explainer",
                      "data",
                      "how_to",
                      "listicle",
                      "myth_fact",
                      "comparison",
                      "promo",
                      "catalog",
                      "testimonial",
                      "story",
                      "opinion",
                      "event"
                    ]
                  },
                  "ideaFormat": {
                    "description": "Format ide brainstorm (dari Ide konten) — dipetakan ke format konten tanpa deteksi AI.",
                    "type": "string",
                    "enum": [
                      "tips",
                      "listicle",
                      "myth",
                      "story",
                      "promo",
                      "behind_the_scenes",
                      "comparison"
                    ]
                  },
                  "similarTo": {
                    "description": "Id carousel referensi \"Buat lagi yang mirip\" (workspace yang sama; selain itu diabaikan). Hanya penanda asal — tidak mengubah isi maupun Credit AI.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "brandId": {
                    "description": "Workspace tujuan (dari GET /v1/brands); bawaan = workspace key / X-Workspace-Id",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
                  },
                  "webhookUrl": {
                    "description": "Override tujuan `carousel.ready` / `carousel.failed` untuk job ini (https publik). Ditandatangani rahasia webhook aktif tertua di workspace — daftarkan webhook dulu lewat POST /webhooks.",
                    "example": "https://n8n.agensi.id/webhook/order-8812",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2048
                  },
                  "strictSlides": {
                    "description": "true = jumlah slide tidak boleh dikurangi diam-diam: bila materi hanya cukup untuk lebih sedikit slide (materi tipis atau slide tanpa fakta dibuang pemeriksa kualitas), carousel `failed` dengan `error.reason: SLIDES_REDUCED` dan Credit AI dikembalikan PENUH. Bawaan (false): slide dikurangi + selisih Credit AI direfund (`slidesReduced`).",
                    "type": "boolean"
                  }
                },
                "required": [
                  "source",
                  "slides",
                  "ratio",
                  "lang"
                ],
                "description": "Buat carousel dari link, teks, ide, atau foto produk. Memakai Credit AI per slide (+ per gambar AI) sesuai tarif admin.",
                "example": {
                  "source": {
                    "type": "link",
                    "value": "https://contoh.id/artikel/pricing-kopi"
                  },
                  "slides": 5,
                  "ratio": "4:5",
                  "lang": "id",
                  "tone": "santai",
                  "images": true
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Diterima (diproses async)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "status": {
                          "type": "string",
                          "const": "queued"
                        },
                        "creditsReserved": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "statusUrl": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "status",
                        "creditsReserved",
                        "statusUrl"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Credit AI kurang (`details.required`, `details.available`) atau kuota klien habis (`details.reason: client_quota`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "60 request/menit per key, 10 generate bersamaan (`details.reason: concurrency`), atau batas harian; lihat `Retry-After`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listCarousels",
        "tags": [
          "Carousels"
        ],
        "summary": "Daftar carousel",
        "description": "Daftar ringkas carousel workspace, terbaru dulu (cursor `meta.nextCursor`).\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/carousels \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Daftar carousel\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/carousels\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 20,
              "description": "Jumlah per halaman (maks 100)",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Jumlah per halaman (maks 100)"
          },
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "Cursor opaque dari `meta.nextCursor`",
              "type": "string",
              "maxLength": 400
            },
            "description": "Cursor opaque dari `meta.nextCursor`"
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "enum": [
                "queued",
                "processing",
                "ready",
                "failed"
              ]
            }
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CarouselSummary"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "nextCursor"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/carousels/{id}": {
      "get": {
        "operationId": "getCarousel",
        "tags": [
          "Carousels"
        ],
        "summary": "Status & isi carousel",
        "description": "`status`: `processing` (slides kosong, ada `progress` 0–100) → `ready` atau `failed`. `workflowStatus` = status alur kerja di Posto (draft, in_review, approved, scheduled, published).\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Status & isi carousel\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Carousel"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateCarousel",
        "tags": [
          "Carousels"
        ],
        "summary": "Ubah teks & desain",
        "description": "Patch parsial: teks per slide (dicocokkan `id`), caption, hashtag, template, aksen, font, rasio, judul. Tanpa Credit AI. Carousel yang masih dibuat → 409.\n\nScope: `create` · Credit AI: 0",
        "x-scope": "create",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X PATCH https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"title\":\"Judul baru\",\"slides\":[{\"id\":\"Vh3kQ9\",\"title\":\"Langkah 1: cek supplier\"}],\"caption\":\"Caption baru…\",\"hashtags\":[\"kopi\"],\"design\":{\"accent\":\"#1F4E3D\",\"ratio\":\"4:5\"}}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'PATCH',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"title\":\"Judul baru\",\"slides\":[{\"id\":\"Vh3kQ9\",\"title\":\"Langkah 1: cek supplier\"}],\"caption\":\"Caption baru…\",\"hashtags\":[\"kopi\"],\"design\":{\"accent\":\"#1F4E3D\",\"ratio\":\"4:5\"}}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Ubah teks & desain\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"PATCH\",\n        \"url\": \"https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"title\\\":\\\"Judul baru\\\",\\\"slides\\\":[{\\\"id\\\":\\\"Vh3kQ9\\\",\\\"title\\\":\\\"Langkah 1: cek supplier\\\"}],\\\"caption\\\":\\\"Caption baru…\\\",\\\"hashtags\\\":[\\\"kopi\\\"],\\\"design\\\":{\\\"accent\\\":\\\"#1F4E3D\\\",\\\"ratio\\\":\\\"4:5\\\"}}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 200,
                    "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                  },
                  "slides": {
                    "maxItems": 13,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "pattern": "^[A-Za-z0-9_-]{4,36}$",
                          "description": "id slide (nanoid)",
                          "example": "Vh3kQ9"
                        },
                        "label": {
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 40,
                              "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "title": {
                          "type": "string",
                          "maxLength": 200,
                          "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                        },
                        "body": {
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 800,
                              "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "cta": {
                          "anyOf": [
                            {
                              "type": "string",
                              "maxLength": 120,
                              "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "video": {
                          "description": "Slide video: klip unggahan menggantikan foto slide (teks template tetap di atas). Potongan ≤ batas paket per slide (Free 30 s, lainnya 60 s); awal dijepret ke keyframe. null = kembali ke gambar.",
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "mediaId": {
                                  "type": "string",
                                  "format": "uuid",
                                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                                  "description": "video unggahan (uploads → media.id)"
                                },
                                "trimStartSec": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 3600
                                },
                                "trimEndSec": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 3600
                                },
                                "muted": {
                                  "type": "boolean"
                                },
                                "coverSec": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 3600
                                }
                              },
                              "required": [
                                "mediaId"
                              ],
                              "additionalProperties": false
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "id"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "caption": {
                    "type": "string",
                    "maxLength": 2200,
                    "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                  },
                  "hashtags": {
                    "maxItems": 30,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^#?[\\p{L}\\p{N}_]{1,60}$"
                    }
                  },
                  "templateId": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                  },
                  "design": {
                    "type": "object",
                    "properties": {
                      "templateId": {
                        "type": "string",
                        "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                      },
                      "accent": {
                        "example": "#1F4E3D",
                        "type": "string",
                        "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
                      },
                      "font": {
                        "type": "string",
                        "enum": [
                          "jakarta",
                          "inter",
                          "bricolage",
                          "anton",
                          "fraunces",
                          "dmserif",
                          "grotesk",
                          "mono"
                        ]
                      },
                      "bodyFont": {
                        "type": "string",
                        "enum": [
                          "jakarta",
                          "inter",
                          "bricolage",
                          "anton",
                          "fraunces",
                          "dmserif",
                          "grotesk",
                          "mono"
                        ]
                      },
                      "ratio": {
                        "type": "string",
                        "enum": [
                          "4:5",
                          "1:1",
                          "9:16"
                        ]
                      }
                    },
                    "additionalProperties": false
                  }
                },
                "additionalProperties": false,
                "example": {
                  "title": "Judul baru",
                  "slides": [
                    {
                      "id": "Vh3kQ9",
                      "title": "Langkah 1: cek supplier"
                    }
                  ],
                  "caption": "Caption baru…",
                  "hashtags": [
                    "kopi"
                  ],
                  "design": {
                    "accent": "#1F4E3D",
                    "ratio": "4:5"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Carousel"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/carousels/{id}/rewrite": {
      "post": {
        "operationId": "rewriteCarousel",
        "tags": [
          "Carousels"
        ],
        "summary": "Opsi teks AI (memakai Credit AI)",
        "description": "Hook, ringkas, panjangkan, variasi, ganti gaya, atau terjemahkan satu field. Aksi teks AI memakai Credit AI dengan tarif yang diatur admin (umumnya 1 per aksi). Tidak mengubah dokumen: pilih opsi lalu PATCH.\n\nScope: `create` · Credit AI: per aksi teks AI (tarif admin)",
        "x-scope": "create",
        "x-credits": "per aksi teks AI (tarif admin)",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/rewrite \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"slideId\":\"Vh3kQ9\",\"field\":\"title\",\"mode\":\"hook\",\"n\":3}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/rewrite', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"slideId\":\"Vh3kQ9\",\"field\":\"title\",\"mode\":\"hook\",\"n\":3}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Opsi teks AI (memakai Credit AI)\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/rewrite\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"slideId\\\":\\\"Vh3kQ9\\\",\\\"field\\\":\\\"title\\\",\\\"mode\\\":\\\"hook\\\",\\\"n\\\":3}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "slideId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,36}$",
                    "description": "id slide (nanoid)",
                    "example": "Vh3kQ9"
                  },
                  "field": {
                    "type": "string",
                    "enum": [
                      "title",
                      "body",
                      "label",
                      "cta",
                      "caption",
                      "hashtags"
                    ]
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "hook",
                      "shorter",
                      "longer",
                      "variations",
                      "tone",
                      "translate"
                    ]
                  },
                  "tone": {
                    "type": "string",
                    "enum": [
                      "santai",
                      "profesional",
                      "edukatif",
                      "storytelling",
                      "jualan",
                      "lucu"
                    ]
                  },
                  "lang": {
                    "type": "string",
                    "enum": [
                      "id",
                      "en",
                      "ms"
                    ]
                  },
                  "n": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 5
                  }
                },
                "required": [
                  "field",
                  "mode"
                ],
                "example": {
                  "slideId": "Vh3kQ9",
                  "field": "title",
                  "mode": "hook",
                  "n": 3
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "options": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      },
                      "required": [
                        "options"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "60 request/menit per key, 10 generate bersamaan (`details.reason: concurrency`), atau batas harian; lihat `Retry-After`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/carousels/{id}/images": {
      "post": {
        "operationId": "generateImage",
        "tags": [
          "Carousels"
        ],
        "summary": "Foto AI untuk satu slide",
        "description": "Memakai Credit AI per gambar dengan tarif yang diatur admin (High lebih mahal dari Standar; umumnya Standar 10, High 30). `tier` wajib eksplisit dan `Idempotency-Key` wajib (pengganti dialog konfirmasi). Hasil terlihat di GET /carousels/{id} (`slides[].imageUrl`).\n\nScope: `create` · Credit AI: per gambar: Standar / High (tarif admin) · `Idempotency-Key` wajib",
        "x-scope": "create",
        "x-credits": "per gambar: Standar / High (tarif admin)",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/images \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Idempotency-Key: order-8812\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"slideId\":\"Vh3kQ9\",\"prompt\":\"barista menuang kopi, cahaya pagi\",\"tier\":\"high\"}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/images', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'order-8812' },\n  body: JSON.stringify({\"slideId\":\"Vh3kQ9\",\"prompt\":\"barista menuang kopi, cahaya pagi\",\"tier\":\"high\"}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Foto AI untuk satu slide\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/images\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendHeaders\": true,\n        \"headerParameters\": {\n          \"parameters\": [\n            {\n              \"name\": \"Idempotency-Key\",\n              \"value\": \"={{ $json.id }}\"\n            }\n          ]\n        },\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"slideId\\\":\\\"Vh3kQ9\\\",\\\"prompt\\\":\\\"barista menuang kopi, cahaya pagi\\\",\\\"tier\\\":\\\"high\\\"}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 128,
              "description": "Wajib. Kunci unik per permintaan (≤ 128 karakter ASCII), disimpan 24 jam."
            },
            "required": true,
            "description": "Wajib. Kunci unik per permintaan (≤ 128 karakter ASCII), disimpan 24 jam."
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "slideId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{4,36}$",
                    "description": "id slide (nanoid)",
                    "example": "Vh3kQ9"
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "photo",
                      "illustration"
                    ]
                  },
                  "prompt": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 600,
                    "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                  },
                  "tier": {
                    "type": "string",
                    "enum": [
                      "standard",
                      "high"
                    ],
                    "description": "standard atau high; High memakai lebih banyak Credit AI (tarif diatur admin)"
                  },
                  "styleKey": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                  }
                },
                "required": [
                  "slideId",
                  "tier"
                ],
                "additionalProperties": false,
                "example": {
                  "slideId": "Vh3kQ9",
                  "prompt": "barista menuang kopi, cahaya pagi",
                  "tier": "high"
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Diterima (diproses async)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "jobId": {
                          "type": "string"
                        },
                        "credits": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "statusUrl": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "jobId",
                        "credits",
                        "statusUrl"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Credit AI kurang (`details.required`, `details.available`) atau kuota klien habis (`details.reason: client_quota`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "60 request/menit per key, 10 generate bersamaan (`details.reason: concurrency`), atau batas harian; lihat `Retry-After`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/carousels/{id}/export": {
      "post": {
        "operationId": "exportCarousel",
        "tags": [
          "Export"
        ],
        "summary": "Buat link unduh",
        "description": "PNG (hanya satu slide), ZIP, atau PDF, dirender di server. Polling GET /carousels/{id}/export/{jobId}; URL berlaku 24 jam. Watermark mengikuti paket.\n\nScope: `create` · Credit AI: 0",
        "x-scope": "create",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/export \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"format\":\"zip\"}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/export', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"format\":\"zip\"}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Buat link unduh\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/export\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"format\\\":\\\"zip\\\"}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "format": {
                    "type": "string",
                    "enum": [
                      "png",
                      "zip",
                      "pdf"
                    ]
                  },
                  "slides": {
                    "description": "Subset slide (urutan dokumen); kosong = semua slide",
                    "minItems": 1,
                    "maxItems": 13,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "pattern": "^[A-Za-z0-9_-]{4,36}$",
                      "description": "id slide (nanoid)",
                      "example": "Vh3kQ9"
                    }
                  }
                },
                "required": [
                  "format"
                ],
                "additionalProperties": false,
                "example": {
                  "format": "zip"
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Diterima (diproses async)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ExportJob"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/carousels/{id}/export/{jobId}": {
      "get": {
        "operationId": "getExport",
        "tags": [
          "Export"
        ],
        "summary": "Status ekspor",
        "description": "`processing` → `done` (`url`, `expiresAt`, `sizeBytes`) atau `failed`.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/export/exp_4f1c0a9b2e7d3c8a11 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/export/exp_4f1c0a9b2e7d3c8a11', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Status ekspor\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/export/exp_4f1c0a9b2e7d3c8a11\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "jobId",
            "schema": {
              "type": "string",
              "pattern": "^exp_[0-9a-f]{18}$",
              "description": "jobId dari POST …/export",
              "example": "exp_4f1c0a9b2e7d3c8a11"
            },
            "required": true,
            "description": "jobId dari POST …/export"
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ExportJob"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/carousels/{id}/video-exports": {
      "post": {
        "operationId": "createVideoExport",
        "tags": [
          "Export"
        ],
        "summary": "Buat video Reels (MP4)",
        "description": "MP4 9:16 1080×1920 (30 fps) dari carousel: slide → video dengan transisi & musik opsional (pustaka CC0). Tanpa Credit AI. Paket Pro, Ultimate, dan Agency (403 `details.feature: \"reels\"`), kuota video harian per paket (429 `details.limit: \"reels_daily\"`), antrean penuh → 503. `id` deterministik per versi + opsi: permintaan yang sama mengembalikan ekspor yang sama (sudah siap = tanpa kuota). Polling GET …/video-exports/{exportId}; link unduh berlaku 24 jam.\n\nScope: `create` · Credit AI: 0 · `Idempotency-Key` opsional",
        "x-scope": "create",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/video-exports \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Idempotency-Key: order-8812\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"fit\":\"auto\",\"secondsPerSlide\":3,\"transition\":\"fade\",\"animation\":\"subtle\",\"musicTrackId\":null,\"musicVolume\":0.7}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/video-exports', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'order-8812' },\n  body: JSON.stringify({\"fit\":\"auto\",\"secondsPerSlide\":3,\"transition\":\"fade\",\"animation\":\"subtle\",\"musicTrackId\":null,\"musicVolume\":0.7}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Buat video Reels (MP4)\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/video-exports\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendHeaders\": true,\n        \"headerParameters\": {\n          \"parameters\": [\n            {\n              \"name\": \"Idempotency-Key\",\n              \"value\": \"={{ $json.id }}\"\n            }\n          ]\n        },\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"fit\\\":\\\"auto\\\",\\\"secondsPerSlide\\\":3,\\\"transition\\\":\\\"fade\\\",\\\"animation\\\":\\\"subtle\\\",\\\"musicTrackId\\\":null,\\\"musicVolume\\\":0.7}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "description": "Opsional (disarankan untuk retry). Kunci sama + body sama → respons tersimpan; body beda → 409. Disimpan 24 jam.",
              "type": "string",
              "maxLength": 128
            },
            "description": "Opsional (disarankan untuk retry). Kunci sama + body sama → respons tersimpan; body beda → 409. Disimpan 24 jam."
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "versionId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "fit": {
                    "default": "auto",
                    "type": "string",
                    "enum": [
                      "auto",
                      "reflow",
                      "frame"
                    ]
                  },
                  "secondsPerSlide": {
                    "default": 3,
                    "type": "number",
                    "minimum": 2,
                    "maximum": 8,
                    "multipleOf": 0.5
                  },
                  "transition": {
                    "default": "fade",
                    "type": "string",
                    "enum": [
                      "none",
                      "fade",
                      "slide"
                    ]
                  },
                  "animation": {
                    "default": "none",
                    "type": "string",
                    "enum": [
                      "none",
                      "subtle",
                      "dynamic"
                    ]
                  },
                  "musicTrackId": {
                    "default": null,
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "musicVolume": {
                    "default": 0.7,
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1
                  }
                },
                "additionalProperties": false,
                "example": {
                  "fit": "auto",
                  "secondsPerSlide": 3,
                  "transition": "fade",
                  "animation": "subtle",
                  "musicTrackId": null,
                  "musicVolume": 0.7
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Diterima (diproses async)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/VideoExport"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "60 request/menit per key, 10 generate bersamaan (`details.reason: concurrency`), atau batas harian; lihat `Retry-After`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/carousels/{id}/video-exports/{exportId}": {
      "get": {
        "operationId": "getVideoExport",
        "tags": [
          "Export"
        ],
        "summary": "Status video Reels",
        "description": "`queued` → `rendering` → `encoding` → `ready` (`video.url`, `video.expiresAt`, durasi, ukuran) atau `failed` (`error.code`: render_failed, encode_failed, timeout, music_unavailable, unknown). `progress` 0–100.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/video-exports/3b9e1f04-6c2d-4a8e-9f17-5d0c2b7a4e91 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/video-exports/3b9e1f04-6c2d-4a8e-9f17-5d0c2b7a4e91', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Status video Reels\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/carousels/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/video-exports/3b9e1f04-6c2d-4a8e-9f17-5d0c2b7a4e91\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "exportId",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22",
              "description": "`id` dari POST …/video-exports"
            },
            "required": true,
            "description": "`id` dari POST …/video-exports"
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/VideoExport"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/videos": {
      "get": {
        "operationId": "listVideos",
        "tags": [
          "Videos"
        ],
        "summary": "Daftar video",
        "description": "Semua video Reels workspace, terbaru dulu: salinan sementara 24 jam (`storage: \"temporary\"`, termasuk yang sedang dibuat/gagal) dan yang tersimpan permanen (`storage: \"saved\"`). Saring `filter`, `carouselId`, `status`; cursor `meta.nextCursor`. Tautan file video tersimpan bertanda tangan 1 jam (`video.linksExpireAt`) — ambil ulang daftar untuk tautan baru.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/videos \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/videos', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Daftar video\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/videos\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "filter",
            "schema": {
              "default": "all",
              "description": "`temporary` = salinan 24 jam, `saved` = tersimpan permanen, `all` = keduanya",
              "type": "string",
              "enum": [
                "all",
                "temporary",
                "saved"
              ]
            },
            "description": "`temporary` = salinan 24 jam, `saved` = tersimpan permanen, `all` = keduanya"
          },
          {
            "in": "query",
            "name": "carouselId",
            "schema": {
              "description": "Hanya video dari carousel ini",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
            },
            "description": "Hanya video dari carousel ini"
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "description": "Hanya status ini (tersimpan selalu `ready`)",
              "type": "string",
              "enum": [
                "queued",
                "rendering",
                "encoding",
                "ready",
                "failed"
              ]
            },
            "description": "Hanya status ini (tersimpan selalu `ready`)"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 20,
              "description": "Jumlah per halaman (maks 50)",
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "description": "Jumlah per halaman (maks 50)"
          },
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "Cursor opaque dari `meta.nextCursor`",
              "type": "string",
              "maxLength": 400
            },
            "description": "Cursor opaque dari `meta.nextCursor`"
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Video"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "nextCursor"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/videos/{id}": {
      "get": {
        "operationId": "getVideo",
        "tags": [
          "Videos"
        ],
        "summary": "Status video",
        "description": "Satu video (id ekspor). Dipakai memantau \"Simpan permanen\": `save.status` `saving` → `saved` (`storage: \"saved\"`, `expiresAt: null`) atau `failed` (`save.error.code`: storage_quota, expired, unknown). Video sementara yang sudah kedaluwarsa → 404.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Status video\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Video"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteVideo",
        "tags": [
          "Videos"
        ],
        "summary": "Hapus video",
        "description": "Video tersimpan → Sampah (kuota penyimpanan langsung kembali; bisa dipulihkan dari Sampah di web 30 hari), `result: \"trashed\"`. Video sementara → disembunyikan dari daftar (kedaluwarsa sendiri ≤ 24 jam), `result: \"hidden\"`. Jadwal Reels tidak terpengaruh.\n\nScope: `create` · Credit AI: 0",
        "x-scope": "create",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X DELETE https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'DELETE',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Hapus video\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"DELETE\",\n        \"url\": \"https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "result": {
                          "type": "string",
                          "enum": [
                            "trashed",
                            "hidden"
                          ],
                          "description": "`trashed` = video tersimpan masuk Sampah (kuota langsung kembali, dipulihkan dari Sampah web 30 hari); `hidden` = video sementara disembunyikan dari daftar (kedaluwarsa sendiri ≤ 24 jam)"
                        }
                      },
                      "required": [
                        "id",
                        "result"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/videos/{id}/save": {
      "post": {
        "operationId": "saveVideo",
        "tags": [
          "Videos"
        ],
        "summary": "Simpan video permanen",
        "description": "Salin video sementara (siap, sisa ≥ 5 menit) ke penyimpanan workspace supaya tidak hilang setelah 24 jam. Memakai kuota penyimpanan paket (±1–15 MB per video): penuh → 403 `storage_quota` (+ `manageUrl`). 202 + `save.status: \"saving\"` selama disalin (pantau GET /videos/{id}); 200 bila sudah tersimpan. Idempoten: panggilan ulang tidak membuat salinan ganda (tanpa Idempotency-Key). Belum siap / kedaluwarsa → 409 `details.reason` `not_ready` | `expired`.\n\nScope: `create` · Credit AI: 0",
        "x-scope": "create",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/save \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/save', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Simpan video permanen\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/videos/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/save\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "202": {
            "description": "Diterima (diproses async)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Video"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/media": {
      "get": {
        "operationId": "listMedia",
        "tags": [
          "Media"
        ],
        "summary": "Daftar gambar",
        "description": "Gambar workspace, terbaru dulu: foto AI & hasil hapus latar (`filter` `all` | `used` | `unused`) atau foto unggahan (`uploads`). `used` = dirujuk carousel aktif atau brand kit; `carousel` + `slide` = asal. `url`/`downloadUrl` bertanda tangan 1 jam (`linksExpireAt`). Cursor `meta.nextCursor`.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/media \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/media', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Daftar gambar\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/media\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "filter",
            "schema": {
              "default": "all",
              "description": "`all` = semua gambar AI, `used` / `unused` = dirujuk / tidak dirujuk carousel aktif atau brand kit, `uploads` = foto unggahan workspace",
              "type": "string",
              "enum": [
                "all",
                "used",
                "unused",
                "uploads"
              ]
            },
            "description": "`all` = semua gambar AI, `used` / `unused` = dirujuk / tidak dirujuk carousel aktif atau brand kit, `uploads` = foto unggahan workspace"
          },
          {
            "in": "query",
            "name": "q",
            "schema": {
              "description": "Cari judul carousel asal",
              "type": "string",
              "maxLength": 120
            },
            "description": "Cari judul carousel asal"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 24,
              "description": "Jumlah per halaman (maks 60)",
              "type": "integer",
              "minimum": 1,
              "maximum": 60
            },
            "description": "Jumlah per halaman (maks 60)"
          },
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "Cursor opaque dari `meta.nextCursor`",
              "type": "string",
              "maxLength": 400
            },
            "description": "Cursor opaque dari `meta.nextCursor`"
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Media"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "nextCursor"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/media/{id}": {
      "delete": {
        "operationId": "deleteMedia",
        "tags": [
          "Media"
        ],
        "summary": "Hapus gambar",
        "description": "Gambar yang tidak dipakai → Sampah 30 hari (kuota langsung kembali, `freedBytes`). Masih dipakai carousel aktif atau brand kit → 409 `media.inUse` dengan `details {reason: \"in_use\", carousels: [{id, title}], brand}` — ganti fotonya di carousel itu dulu.\n\nScope: `create` · Credit AI: 0",
        "x-scope": "create",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X DELETE https://posto.id/api/v1/media/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/media/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'DELETE',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Hapus gambar\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"DELETE\",\n        \"url\": \"https://posto.id/api/v1/media/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "freedBytes": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Kuota penyimpanan yang langsung kembali"
                        }
                      },
                      "required": [
                        "id",
                        "freedBytes"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/uploads": {
      "post": {
        "operationId": "createUpload",
        "tags": [
          "Uploads"
        ],
        "summary": "Minta URL unggah konten sendiri",
        "description": "Unggah foto/video sendiri untuk posting (PR-B): kirim nama, mime, ukuran (byte) dan — untuk video — durasi/dimensi bila diketahui (penolakan dini). Respons: `uploadUrl` + `headers` (PUT berkas mentah, berlaku 15 menit), lalu `POST /uploads/{id}/complete`. Diterima: JPG/PNG/WebP/HEIC ≤ 20 MB (disimpan JPG); MP4/MOV H.264/HEVC + AAC/tanpa audio, sisi terpanjang ≤ 1920 px, ≤ 60 fps, rasio 9:16–16:9, ukuran & durasi ≤ batas paket (`limits`). Ditolak → 422 `error.reason` (mis. `VIDEO_CODEC_NOT_SUPPORTED`, `VIDEO_RESOLUTION_TOO_HIGH`) + `fix`. Memakai kuota penyimpanan.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/uploads \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"filename\":\"promo.mp4\",\"mime\":\"video/mp4\",\"size\":18400000,\"durationSec\":24.5,\"width\":1080,\"height\":1920}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/uploads', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"filename\":\"promo.mp4\",\"mime\":\"video/mp4\",\"size\":18400000,\"durationSec\":24.5,\"width\":1080,\"height\":1920}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Minta URL unggah konten sendiri\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/uploads\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"filename\\\":\\\"promo.mp4\\\",\\\"mime\\\":\\\"video/mp4\\\",\\\"size\\\":18400000,\\\"durationSec\\\":24.5,\\\"width\\\":1080,\\\"height\\\":1920}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "filename": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255
                  },
                  "mime": {
                    "default": "",
                    "type": "string",
                    "maxLength": 100
                  },
                  "size": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 9007199254740991
                  },
                  "durationSec": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 86400
                  },
                  "width": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 20000
                  },
                  "height": {
                    "type": "integer",
                    "exclusiveMinimum": 0,
                    "maximum": 20000
                  },
                  "brandId": {
                    "description": "Workspace tujuan; bawaan = workspace key / X-Workspace-Id",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
                  }
                },
                "required": [
                  "filename",
                  "size"
                ],
                "additionalProperties": false,
                "example": {
                  "filename": "promo.mp4",
                  "mime": "video/mp4",
                  "size": 18400000,
                  "durationSec": 24.5,
                  "width": 1080,
                  "height": 1920
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Dibuat",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadCreated"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "60 request/menit per key, 10 generate bersamaan (`details.reason: concurrency`), atau batas harian; lihat `Retry-After`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/uploads/{id}/complete": {
      "post": {
        "operationId": "completeUpload",
        "tags": [
          "Uploads"
        ],
        "summary": "Selesaikan unggahan",
        "description": "Setelah PUT selesai. Gambar umumnya langsung `ready`; HEIC & video diperiksa (ffprobe) lalu disiapkan TANPA encode ulang (remux MOV→MP4 + faststart) → `processing`, poll `GET /uploads/{id}`. Ditolak → `status: \"rejected\"` + `rejection.message` (cara memperbaiki). Idempoten.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/uploads/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/complete \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/uploads/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/complete', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Selesaikan unggahan\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/uploads/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/complete\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadStatus"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/uploads/{id}": {
      "get": {
        "operationId": "getUpload",
        "tags": [
          "Uploads"
        ],
        "summary": "Status unggahan",
        "description": "`uploading` | `processing` | `ready` (`media.id` = mediaId untuk `POST /schedules` `media[]`; video: durasi, fps, keyframe untuk memotong) | `rejected` (alasan + cara memperbaiki).\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/uploads/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/uploads/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Status unggahan\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/uploads/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadStatus"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/schedules": {
      "post": {
        "operationId": "createSchedule",
        "tags": [
          "Schedules"
        ],
        "summary": "Jadwalkan posting",
        "description": "Akun dipilih otomatis bila workspace punya tepat satu akun aktif per platform; selain itu isi `accounts.<platform>` = accountId, array accountId, atau `\"all\"` (GET /accounts). SEMUA masalah dikembalikan sekaligus dalam satu 422: `error.reason` (mis. `AMBIGUOUS_ACCOUNT`, `CAPTION_TOO_LONG`, `MULTIPLE_ISSUES`), `error.fix`, `details.issues[]` (`reason`, `path`, `message`, `fix`, `platform`, `accountId`, `candidates`); `details.ambiguousPlatforms`/`missingPlatforms` tetap ada. `skipInvalid: true` → target valid tetap dijadwalkan (`skipped[]`). `publishAt` ≥ 5 menit dari sekarang, atau `publishNow: true`. `autoFitCaptions: true` meringkas caption yang melebihi batas platform (`captionAdjustments[]`). Workspace dengan approval wajib → carousel harus `approved` (403 `approval_required`). TikTok wajib `tiktok.privacyLevel` dari `allowedPrivacyLevels` (GET /accounts/{id}/tiktok-creator-info). `format: \"reels\"` (+ `video`) = diposting sebagai video Reels (paket Pro, Ultimate, dan Agency; 403 `details.feature: \"reels\"`). Posting media sendiri (PR-B): kirim `media[]` (unggahan `ready`, urut; potong/sampul/bisukan video tanpa encode ulang) alih-alih `carouselId`; platform yang tidak mendukung isinya ditolak per target (`MIXED_MEDIA_NOT_SUPPORTED` Facebook/TikTok foto+video, `TOO_MANY_VIDEOS`, `TOO_MANY_ITEMS`, `RATIO_NOT_SUPPORTED`, `VIDEO_TOO_LONG`, …) — `skipInvalid` berlaku sama.\n\nScope: `schedule` · Credit AI: 0 · `Idempotency-Key` opsional",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/schedules \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Idempotency-Key: order-8812\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"carouselId\":\"7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\"platforms\":[\"instagram\",\"threads\"],\"publishAt\":\"2026-10-17T12:30:00Z\",\"captions\":{\"instagram\":\"Caption IG…\",\"threads\":\"Versi pendek…\"}}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedules', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'order-8812' },\n  body: JSON.stringify({\"carouselId\":\"7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\"platforms\":[\"instagram\",\"threads\"],\"publishAt\":\"2026-10-17T12:30:00Z\",\"captions\":{\"instagram\":\"Caption IG…\",\"threads\":\"Versi pendek…\"}}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Jadwalkan posting\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/schedules\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendHeaders\": true,\n        \"headerParameters\": {\n          \"parameters\": [\n            {\n              \"name\": \"Idempotency-Key\",\n              \"value\": \"={{ $json.id }}\"\n            }\n          ]\n        },\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"carouselId\\\":\\\"7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\\\",\\\"platforms\\\":[\\\"instagram\\\",\\\"threads\\\"],\\\"publishAt\\\":\\\"2026-10-17T12:30:00Z\\\",\\\"captions\\\":{\\\"instagram\\\":\\\"Caption IG…\\\",\\\"threads\\\":\\\"Versi pendek…\\\"}}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "description": "Opsional (disarankan untuk retry). Kunci sama + body sama → respons tersimpan; body beda → 409. Disimpan 24 jam.",
              "type": "string",
              "maxLength": 128
            },
            "description": "Opsional (disarankan untuk retry). Kunci sama + body sama → respons tersimpan; body beda → 409. Disimpan 24 jam."
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "carouselId": {
                    "description": "Carousel Posto yang diposting. Isi ini ATAU `media`.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
                  },
                  "media": {
                    "description": "Posting media sendiri (PR-B): gambar/video unggahan berurutan (1 = foto/video tunggal, ≥ 2 = carousel). Isi ini ATAU `carouselId`. Platform yang tidak mendukung isi ini (mis. Facebook/TikTok: foto + video dalam satu posting) → 422 dengan reason & fix.",
                    "minItems": 1,
                    "maxItems": 35,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "mediaId": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                          "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22",
                          "description": "uploadId/mediaId dari POST /uploads yang sudah berstatus ready"
                        },
                        "trimStartSec": {
                          "description": "Video: awal potongan (detik); dimundurkan ke keyframe terdekat (tanpa encode ulang)",
                          "type": "number",
                          "minimum": 0,
                          "maximum": 86400
                        },
                        "trimEndSec": {
                          "description": "Video: akhir potongan (detik)",
                          "type": "number",
                          "minimum": 0,
                          "maximum": 86400
                        },
                        "muted": {
                          "description": "Video: true = suara dibuang",
                          "type": "boolean"
                        },
                        "coverSec": {
                          "description": "Video: frame sampul (detik dari awal video asli; Instagram & TikTok)",
                          "type": "number",
                          "minimum": 0,
                          "maximum": 86400
                        }
                      },
                      "required": [
                        "mediaId"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "platforms": {
                    "minItems": 1,
                    "maxItems": 4,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    }
                  },
                  "captions": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    },
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 5000,
                      "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                    }
                  },
                  "accounts": {
                    "description": "platform → accountId, array accountId, atau \"all\" (semua akun aktif). Wajib bila brand punya lebih dari satu akun aktif di platform itu (422 `AMBIGUOUS_ACCOUNT` + `candidates`). Daftar akun: GET /accounts.",
                    "example": {
                      "facebook": [
                        "5c2e9d1a-0b7f-4c3e-9a2d-1f8e6b4c7a90",
                        "6d3f0e2b-1c8a-4d4f-8b3e-2a9f7c5d8b01"
                      ]
                    },
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    },
                    "additionalProperties": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        {
                          "minItems": 1,
                          "maxItems": 10,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          }
                        },
                        {
                          "type": "string",
                          "const": "all"
                        }
                      ]
                    }
                  },
                  "tiktok": {
                    "description": "Wajib untuk TikTok. `privacyLevel` (PUBLIC_TO_EVERYONE | MUTUAL_FOLLOW_FRIENDS | FOLLOWER_OF_CREATOR | SELF_ONLY) dipilih user tanpa nilai bawaan dan harus salah satu `allowedPrivacyLevels` dari GET /accounts/{id}/tiktok-creator-info. `disableComment` (bawaan true = komentar mati), `disableDuet`/`disableStitch` (video Reels; bawaan true) — tidak boleh dinyalakan bila kreator mematikannya. Pengungkapan konten komersial: `brandOrganic` (promosi bisnis sendiri → label \"Promotional content\"), `brandContent` (pihak ketiga → \"Paid partnership\", tidak boleh SELF_ONLY). Foto saja: `title` ≤ 90, `autoAddMusic`. Dengan memposting, user menyetujui Music Usage Confirmation TikTok (+ Branded Content Policy untuk brandContent). Berlaku untuk semua akun TikTok jadwal.",
                    "type": "object",
                    "properties": {
                      "privacyLevel": {
                        "type": "string",
                        "enum": [
                          "PUBLIC_TO_EVERYONE",
                          "MUTUAL_FOLLOW_FRIENDS",
                          "FOLLOWER_OF_CREATOR",
                          "SELF_ONLY"
                        ]
                      },
                      "disableComment": {
                        "type": "boolean"
                      },
                      "brandContent": {
                        "type": "boolean"
                      },
                      "brandOrganic": {
                        "type": "boolean"
                      },
                      "autoAddMusic": {
                        "type": "boolean"
                      },
                      "title": {
                        "type": "string",
                        "maxLength": 90
                      },
                      "disableDuet": {
                        "type": "boolean"
                      },
                      "disableStitch": {
                        "type": "boolean"
                      }
                    },
                    "required": [
                      "privacyLevel"
                    ]
                  },
                  "publishAt": {
                    "description": "ISO 8601 (UTC atau dengan offset), ≥ 5 menit dari sekarang. Wajib kecuali `publishNow: true`.",
                    "type": "string",
                    "format": "date-time",
                    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                    "example": "2026-10-17T12:30:00Z"
                  },
                  "timezone": {
                    "description": "Zona waktu IANA; bawaan zona workspace",
                    "example": "Asia/Jakarta",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  },
                  "format": {
                    "description": "`carousel` (bawaan) atau `reels` = video MP4 9:16 dari carousel, dibuat saat posting dan diposting sebagai Reels (IG/FB), video (Threads), atau video TikTok. Reels butuh paket Pro, Ultimate, atau Agency.",
                    "type": "string",
                    "enum": [
                      "carousel",
                      "reels"
                    ]
                  },
                  "video": {
                    "description": "Opsi video, hanya dibaca untuk `format: \"reels\"` (kosong = bawaan: fit auto, 3 detik per slide, transisi pudar, tanpa animasi, tanpa musik). `animation`: `none` | `subtle` (teks masuk bertahap halus + foto zoom pelan) | `dynamic` (lebih cepat & terasa). `musicTrackId` butuh musik aktif.",
                    "example": {
                      "fit": "auto",
                      "secondsPerSlide": 3,
                      "transition": "fade",
                      "animation": "subtle",
                      "musicTrackId": null,
                      "musicVolume": 0.7
                    },
                    "type": "object",
                    "properties": {
                      "fit": {
                        "default": "auto",
                        "type": "string",
                        "enum": [
                          "auto",
                          "reflow",
                          "frame"
                        ]
                      },
                      "secondsPerSlide": {
                        "default": 3,
                        "type": "number",
                        "minimum": 2,
                        "maximum": 8,
                        "multipleOf": 0.5
                      },
                      "transition": {
                        "default": "fade",
                        "type": "string",
                        "enum": [
                          "none",
                          "fade",
                          "slide"
                        ]
                      },
                      "animation": {
                        "default": "none",
                        "type": "string",
                        "enum": [
                          "none",
                          "subtle",
                          "dynamic"
                        ]
                      },
                      "musicTrackId": {
                        "default": null,
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "musicVolume": {
                        "default": 0.7,
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      }
                    }
                  },
                  "publishNow": {
                    "description": "true = posting sekarang (tanpa `publishAt`): jadwal dibuat lalu langsung diproses, sama dengan tombol \"Posting sekarang\" di web.",
                    "type": "boolean"
                  },
                  "skipInvalid": {
                    "description": "true = target yang bermasalah (akun putus, caption terlalu panjang, …) dilewati; target valid tetap dijadwalkan. Daftar yang dilewati di `skipped[]`. Masalah jadwal (waktu, carousel belum siap) tetap menggagalkan semua.",
                    "type": "boolean"
                  },
                  "autoFitCaptions": {
                    "description": "true = caption yang melebihi batas platform diringkas otomatis (hashtag dikurangi dulu, lalu dipotong per kalimat utuh); perubahannya di `captionAdjustments[]`.",
                    "type": "boolean"
                  }
                },
                "required": [
                  "platforms"
                ],
                "additionalProperties": false,
                "example": {
                  "carouselId": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22",
                  "platforms": [
                    "instagram",
                    "threads"
                  ],
                  "publishAt": "2026-10-17T12:30:00Z",
                  "captions": {
                    "instagram": "Caption IG…",
                    "threads": "Versi pendek…"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Dibuat",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduleCreated"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listSchedules",
        "tags": [
          "Schedules"
        ],
        "summary": "Daftar jadwal",
        "description": "Bawaan 7 hari lalu s/d 35 hari ke depan. Saring `status`, `platform` (jadwal yang punya target di platform itu), `carouselId`.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/schedules \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedules', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Daftar jadwal\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/schedules\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "from",
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
              "example": "2026-10-17T12:30:00Z"
            }
          },
          {
            "in": "query",
            "name": "to",
            "schema": {
              "type": "string",
              "format": "date-time",
              "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
              "example": "2026-10-17T12:30:00Z"
            }
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "enum": [
                "scheduled",
                "rendering",
                "publishing",
                "published",
                "failed",
                "canceled"
              ]
            }
          },
          {
            "in": "query",
            "name": "platform",
            "schema": {
              "type": "string",
              "enum": [
                "instagram",
                "facebook",
                "threads",
                "tiktok"
              ]
            }
          },
          {
            "in": "query",
            "name": "carouselId",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
            }
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Schedule"
                      }
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/schedules/{id}": {
      "get": {
        "operationId": "getSchedule",
        "tags": [
          "Schedules"
        ],
        "summary": "Status jadwal",
        "description": "`targets[]` per akun: status, `externalId`, `permalink`, error, jumlah percobaan, `format` dan `reelsStep` (video → upload → processing → published). `seriesId` bila kejadian jadwal berulang.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Status jadwal\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Schedule"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateSchedule",
        "tags": [
          "Schedules"
        ],
        "summary": "Ubah jadwal",
        "description": "Ubah waktu (`publishAt`, `timezone`), caption per platform jadwal (`captions`, + `autoFitCaptions`), opsi TikTok, atau format (`format: \"reels\"` + `video`). Akun tidak bisa diganti. Hanya sebelum diproses atau setelah gagal (jadwal gagal: hanya target yang gagal yang berubah); selain itu 409 (`error.reason: NOT_EDITABLE`).\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X PATCH https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"publishAt\":\"2026-10-18T12:30:00Z\",\"format\":\"reels\",\"video\":{\"secondsPerSlide\":4,\"transition\":\"slide\"}}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'PATCH',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"publishAt\":\"2026-10-18T12:30:00Z\",\"format\":\"reels\",\"video\":{\"secondsPerSlide\":4,\"transition\":\"slide\"}}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Ubah jadwal\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"PATCH\",\n        \"url\": \"https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"publishAt\\\":\\\"2026-10-18T12:30:00Z\\\",\\\"format\\\":\\\"reels\\\",\\\"video\\\":{\\\"secondsPerSlide\\\":4,\\\"transition\\\":\\\"slide\\\"}}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "publishAt": {
                    "type": "string",
                    "format": "date-time",
                    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
                    "example": "2026-10-17T12:30:00Z"
                  },
                  "timezone": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  },
                  "captions": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    },
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 5000,
                      "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                    }
                  },
                  "tiktok": {
                    "type": "object",
                    "properties": {
                      "privacyLevel": {
                        "type": "string",
                        "enum": [
                          "PUBLIC_TO_EVERYONE",
                          "MUTUAL_FOLLOW_FRIENDS",
                          "FOLLOWER_OF_CREATOR",
                          "SELF_ONLY"
                        ]
                      },
                      "disableComment": {
                        "type": "boolean"
                      },
                      "brandContent": {
                        "type": "boolean"
                      },
                      "brandOrganic": {
                        "type": "boolean"
                      },
                      "autoAddMusic": {
                        "type": "boolean"
                      },
                      "title": {
                        "type": "string",
                        "maxLength": 90
                      },
                      "disableDuet": {
                        "type": "boolean"
                      },
                      "disableStitch": {
                        "type": "boolean"
                      }
                    },
                    "required": [
                      "privacyLevel"
                    ]
                  },
                  "format": {
                    "description": "`carousel` (bawaan) atau `reels` = video MP4 9:16 dari carousel, dibuat saat posting dan diposting sebagai Reels (IG/FB), video (Threads), atau video TikTok. Reels butuh paket Pro, Ultimate, atau Agency.",
                    "type": "string",
                    "enum": [
                      "carousel",
                      "reels"
                    ]
                  },
                  "video": {
                    "description": "Opsi video, hanya dibaca untuk `format: \"reels\"` (kosong = bawaan: fit auto, 3 detik per slide, transisi pudar, tanpa animasi, tanpa musik). `animation`: `none` | `subtle` (teks masuk bertahap halus + foto zoom pelan) | `dynamic` (lebih cepat & terasa). `musicTrackId` butuh musik aktif.",
                    "example": {
                      "fit": "auto",
                      "secondsPerSlide": 3,
                      "transition": "fade",
                      "animation": "subtle",
                      "musicTrackId": null,
                      "musicVolume": 0.7
                    },
                    "type": "object",
                    "properties": {
                      "fit": {
                        "default": "auto",
                        "type": "string",
                        "enum": [
                          "auto",
                          "reflow",
                          "frame"
                        ]
                      },
                      "secondsPerSlide": {
                        "default": 3,
                        "type": "number",
                        "minimum": 2,
                        "maximum": 8,
                        "multipleOf": 0.5
                      },
                      "transition": {
                        "default": "fade",
                        "type": "string",
                        "enum": [
                          "none",
                          "fade",
                          "slide"
                        ]
                      },
                      "animation": {
                        "default": "none",
                        "type": "string",
                        "enum": [
                          "none",
                          "subtle",
                          "dynamic"
                        ]
                      },
                      "musicTrackId": {
                        "default": null,
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "musicVolume": {
                        "default": 0.7,
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      }
                    }
                  },
                  "autoFitCaptions": {
                    "description": "true = caption di `captions` yang melebihi batas platform diringkas otomatis (ADR 0080)",
                    "type": "boolean"
                  }
                },
                "additionalProperties": false,
                "example": {
                  "publishAt": "2026-10-18T12:30:00Z",
                  "format": "reels",
                  "video": {
                    "secondsPerSlide": 4,
                    "transition": "slide"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "carouselId": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "null = posting media sendiri (`kind: \"upload\"`, PR-B)"
                        },
                        "carouselTitle": {
                          "type": "string",
                          "description": "Judul carousel (MCP-A, aditif); posting media sendiri: potongan caption"
                        },
                        "kind": {
                          "type": "string",
                          "enum": [
                            "carousel",
                            "upload",
                            "thread"
                          ],
                          "description": "PR-B (aditif): `upload` = posting media sendiri. UT-4 (aditif): `thread` = utas Threads (dibuat dari web; hanya waktu yang bisa diubah lewat API)"
                        },
                        "media": {
                          "anyOf": [
                            {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "mediaId": {
                                    "type": "string",
                                    "format": "uuid",
                                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                                  },
                                  "type": {
                                    "type": "string",
                                    "enum": [
                                      "image",
                                      "video"
                                    ]
                                  },
                                  "durationSec": {
                                    "description": "Video: durasi potongan (detik)",
                                    "type": [
                                      "number",
                                      "null"
                                    ]
                                  },
                                  "trimStartSec": {
                                    "type": [
                                      "number",
                                      "null"
                                    ]
                                  },
                                  "trimEndSec": {
                                    "type": [
                                      "number",
                                      "null"
                                    ]
                                  },
                                  "muted": {
                                    "type": "boolean"
                                  },
                                  "coverSec": {
                                    "type": [
                                      "number",
                                      "null"
                                    ]
                                  },
                                  "missing": {
                                    "type": "boolean",
                                    "description": "Media sudah dihapus (posting akan gagal MEDIA_MISSING)"
                                  }
                                },
                                "required": [
                                  "mediaId",
                                  "type",
                                  "durationSec",
                                  "trimStartSec",
                                  "trimEndSec",
                                  "muted",
                                  "coverSec",
                                  "missing"
                                ]
                              }
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "Item posting media sendiri; null = carousel"
                        },
                        "thread": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "postThreadId": {
                                  "type": "string",
                                  "format": "uuid",
                                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                                },
                                "postCount": {
                                  "type": "integer",
                                  "minimum": -9007199254740991,
                                  "maximum": 9007199254740991
                                },
                                "title": {
                                  "type": "string"
                                }
                              },
                              "required": [
                                "postThreadId",
                                "postCount",
                                "title"
                              ]
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "Utas Threads (UT-4, aditif): id utas, jumlah posting, judul internal; null = bukan utas"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "scheduled",
                            "rendering",
                            "publishing",
                            "published",
                            "failed",
                            "canceled"
                          ]
                        },
                        "paused": {
                          "type": "boolean",
                          "description": "Dijeda karena paket berakhir (aditif): `status` tetap `canceled` dan target ber-`error.code` `SUBSCRIPTION_PAUSED`. Pulih otomatis menjadi `scheduled` saat paket dibayar bila `publishAt` masih di depan; yang waktunya sudah lewat menjadi `failed` dengan `SUBSCRIPTION_MISSED` (tidak diposting terlambat; jadwalkan ulang)"
                        },
                        "publishAt": {
                          "type": "string"
                        },
                        "format": {
                          "type": "string",
                          "enum": [
                            "carousel",
                            "reels"
                          ]
                        },
                        "video": {
                          "anyOf": [
                            {
                              "type": "object",
                              "properties": {
                                "fit": {
                                  "type": "string",
                                  "enum": [
                                    "auto",
                                    "reflow",
                                    "frame"
                                  ]
                                },
                                "secondsPerSlide": {
                                  "type": "number"
                                },
                                "transition": {
                                  "type": "string",
                                  "enum": [
                                    "none",
                                    "fade",
                                    "slide"
                                  ]
                                },
                                "animation": {
                                  "description": "Animasi isi slide (M7-04); jadwal lama tanpa kunci ini = `none`",
                                  "type": "string",
                                  "enum": [
                                    "none",
                                    "subtle",
                                    "dynamic"
                                  ]
                                },
                                "musicTrackId": {
                                  "anyOf": [
                                    {
                                      "type": "string",
                                      "format": "uuid",
                                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                                    },
                                    {
                                      "type": "null"
                                    }
                                  ]
                                },
                                "musicVolume": {
                                  "type": "number"
                                }
                              },
                              "required": [
                                "fit",
                                "secondsPerSlide",
                                "transition",
                                "musicTrackId",
                                "musicVolume"
                              ]
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "Opsi video (hanya `reels`)"
                        },
                        "videoDurationSec": {
                          "description": "Perkiraan durasi video (detik); null = carousel",
                          "type": [
                            "number",
                            "null"
                          ]
                        },
                        "seriesId": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "Seri jadwal berulang asal; null = jadwal biasa"
                        },
                        "seriesSeq": {
                          "anyOf": [
                            {
                              "type": "integer",
                              "minimum": -9007199254740991,
                              "maximum": 9007199254740991
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "targets": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "platform": {
                                "type": "string",
                                "enum": [
                                  "instagram",
                                  "facebook",
                                  "threads",
                                  "tiktok"
                                ]
                              },
                              "accountId": {
                                "type": "string",
                                "format": "uuid",
                                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                              },
                              "handle": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "status": {
                                "type": "string",
                                "enum": [
                                  "scheduled",
                                  "rendering",
                                  "publishing",
                                  "published",
                                  "failed",
                                  "canceled"
                                ]
                              },
                              "externalId": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "permalink": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "publishedAt": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "error": {
                                "anyOf": [
                                  {
                                    "type": "object",
                                    "properties": {
                                      "code": {
                                        "type": "string"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    },
                                    "required": [
                                      "code",
                                      "message"
                                    ]
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "attempts": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "caption": {
                                "type": "string",
                                "description": "Caption yang akan/sudah diposting ke akun ini (MCP-A, aditif)"
                              },
                              "format": {
                                "type": "string",
                                "enum": [
                                  "carousel",
                                  "reels"
                                ]
                              },
                              "reelsStep": {
                                "anyOf": [
                                  {
                                    "type": "string",
                                    "enum": [
                                      "video",
                                      "upload",
                                      "processing",
                                      "published"
                                    ]
                                  },
                                  {
                                    "type": "null"
                                  }
                                ],
                                "description": "Progres Reels: video → upload → processing → published; null = carousel / belum mulai"
                              }
                            },
                            "required": [
                              "platform",
                              "accountId",
                              "handle",
                              "status",
                              "externalId",
                              "permalink",
                              "publishedAt",
                              "error",
                              "attempts",
                              "caption",
                              "format",
                              "reelsStep"
                            ]
                          }
                        },
                        "calendarUrl": {
                          "type": "string"
                        },
                        "captionAdjustments": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "platform": {
                                "type": "string",
                                "enum": [
                                  "instagram",
                                  "facebook",
                                  "threads",
                                  "tiktok"
                                ]
                              },
                              "accountId": {
                                "type": "string",
                                "format": "uuid",
                                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                              },
                              "limit": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "originalLength": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "length": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "hashtagsRemoved": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "sentencesRemoved": {
                                "type": "integer",
                                "minimum": -9007199254740991,
                                "maximum": 9007199254740991
                              },
                              "cutMidSentence": {
                                "type": "boolean"
                              },
                              "caption": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "platform",
                              "accountId",
                              "limit",
                              "originalLength",
                              "length",
                              "hashtagsRemoved",
                              "sentencesRemoved",
                              "cutMidSentence",
                              "caption"
                            ]
                          },
                          "description": "Caption yang diringkas (`autoFitCaptions: true`)"
                        }
                      },
                      "required": [
                        "id",
                        "carouselId",
                        "carouselTitle",
                        "kind",
                        "media",
                        "thread",
                        "status",
                        "paused",
                        "publishAt",
                        "format",
                        "video",
                        "videoDurationSec",
                        "seriesId",
                        "seriesSeq",
                        "targets",
                        "calendarUrl",
                        "captionAdjustments"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "cancelSchedule",
        "tags": [
          "Schedules"
        ],
        "summary": "Batalkan jadwal",
        "description": "Hanya saat `scheduled` atau `failed`; sedang diposting → 409.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X DELETE https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'DELETE',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Batalkan jadwal\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"DELETE\",\n        \"url\": \"https://posto.id/api/v1/schedules/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "status": {
                          "type": "string",
                          "const": "canceled"
                        }
                      },
                      "required": [
                        "id",
                        "status"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/schedule-series": {
      "post": {
        "operationId": "createScheduleSeries",
        "tags": [
          "Series"
        ],
        "summary": "Buat jadwal berulang",
        "description": "Posting ULANG carousel yang sama menurut aturan (harian/mingguan/bulanan, jam lokal zona seri, akhir `until`/`count` opsional) ke akun yang dipilih seperti POST /schedules. Kejadian dalam 14 hari ke depan langsung masuk kalender (GET /schedules, `seriesId`), sisanya bergulir otomatis. `format: \"reels\"` = tiap kejadian diposting sebagai video. Paket berbayar + batas seri per paket (403 `details.reason`: plan | series_limit | feature_off).\n\nScope: `schedule` · Credit AI: 0 · `Idempotency-Key` opsional",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/schedule-series \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Idempotency-Key: order-8812\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"carouselId\":\"7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\"platforms\":[\"instagram\"],\"rule\":{\"freq\":\"weekly\",\"interval\":1,\"byWeekday\":[1,4],\"time\":\"19:00\",\"count\":8},\"startsOn\":\"2026-10-20\",\"format\":\"reels\"}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedule-series', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'order-8812' },\n  body: JSON.stringify({\"carouselId\":\"7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\"platforms\":[\"instagram\"],\"rule\":{\"freq\":\"weekly\",\"interval\":1,\"byWeekday\":[1,4],\"time\":\"19:00\",\"count\":8},\"startsOn\":\"2026-10-20\",\"format\":\"reels\"}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Buat jadwal berulang\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/schedule-series\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendHeaders\": true,\n        \"headerParameters\": {\n          \"parameters\": [\n            {\n              \"name\": \"Idempotency-Key\",\n              \"value\": \"={{ $json.id }}\"\n            }\n          ]\n        },\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"carouselId\\\":\\\"7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\\\",\\\"platforms\\\":[\\\"instagram\\\"],\\\"rule\\\":{\\\"freq\\\":\\\"weekly\\\",\\\"interval\\\":1,\\\"byWeekday\\\":[1,4],\\\"time\\\":\\\"19:00\\\",\\\"count\\\":8},\\\"startsOn\\\":\\\"2026-10-20\\\",\\\"format\\\":\\\"reels\\\"}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "description": "Opsional (disarankan untuk retry). Kunci sama + body sama → respons tersimpan; body beda → 409. Disimpan 24 jam.",
              "type": "string",
              "maxLength": 128
            },
            "description": "Opsional (disarankan untuk retry). Kunci sama + body sama → respons tersimpan; body beda → 409. Disimpan 24 jam."
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "carouselId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
                  },
                  "platforms": {
                    "minItems": 1,
                    "maxItems": 4,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    }
                  },
                  "captions": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    },
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 5000,
                      "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                    }
                  },
                  "accounts": {
                    "description": "platform → accountId, array accountId, atau \"all\" (semua akun aktif). Wajib bila brand punya lebih dari satu akun aktif di platform itu (422 `AMBIGUOUS_ACCOUNT` + `candidates`). Daftar akun: GET /accounts.",
                    "example": {
                      "facebook": [
                        "5c2e9d1a-0b7f-4c3e-9a2d-1f8e6b4c7a90",
                        "6d3f0e2b-1c8a-4d4f-8b3e-2a9f7c5d8b01"
                      ]
                    },
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    },
                    "additionalProperties": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        {
                          "minItems": 1,
                          "maxItems": 10,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          }
                        },
                        {
                          "type": "string",
                          "const": "all"
                        }
                      ]
                    }
                  },
                  "tiktok": {
                    "description": "Wajib untuk TikTok. `privacyLevel` (PUBLIC_TO_EVERYONE | MUTUAL_FOLLOW_FRIENDS | FOLLOWER_OF_CREATOR | SELF_ONLY) dipilih user tanpa nilai bawaan dan harus salah satu `allowedPrivacyLevels` dari GET /accounts/{id}/tiktok-creator-info. `disableComment` (bawaan true = komentar mati), `disableDuet`/`disableStitch` (video Reels; bawaan true) — tidak boleh dinyalakan bila kreator mematikannya. Pengungkapan konten komersial: `brandOrganic` (promosi bisnis sendiri → label \"Promotional content\"), `brandContent` (pihak ketiga → \"Paid partnership\", tidak boleh SELF_ONLY). Foto saja: `title` ≤ 90, `autoAddMusic`. Dengan memposting, user menyetujui Music Usage Confirmation TikTok (+ Branded Content Policy untuk brandContent). Berlaku untuk semua akun TikTok jadwal.",
                    "type": "object",
                    "properties": {
                      "privacyLevel": {
                        "type": "string",
                        "enum": [
                          "PUBLIC_TO_EVERYONE",
                          "MUTUAL_FOLLOW_FRIENDS",
                          "FOLLOWER_OF_CREATOR",
                          "SELF_ONLY"
                        ]
                      },
                      "disableComment": {
                        "type": "boolean"
                      },
                      "brandContent": {
                        "type": "boolean"
                      },
                      "brandOrganic": {
                        "type": "boolean"
                      },
                      "autoAddMusic": {
                        "type": "boolean"
                      },
                      "title": {
                        "type": "string",
                        "maxLength": 90
                      },
                      "disableDuet": {
                        "type": "boolean"
                      },
                      "disableStitch": {
                        "type": "boolean"
                      }
                    },
                    "required": [
                      "privacyLevel"
                    ]
                  },
                  "rule": {
                    "type": "object",
                    "properties": {
                      "freq": {
                        "type": "string",
                        "enum": [
                          "daily",
                          "weekly",
                          "monthly"
                        ]
                      },
                      "interval": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 4
                      },
                      "byWeekday": {
                        "minItems": 1,
                        "maxItems": 7,
                        "type": "array",
                        "items": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 6
                        }
                      },
                      "byMonthDay": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      "time": {
                        "type": "string"
                      },
                      "until": {
                        "type": "string",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                      },
                      "count": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 100
                      }
                    },
                    "required": [
                      "freq",
                      "interval",
                      "time"
                    ],
                    "description": "`freq` daily|weekly|monthly, `interval` 1–4, `byWeekday` (0 = Minggu … 6 = Sabtu, wajib untuk weekly), `byMonthDay` (1–28 atau -1 = hari terakhir, wajib untuk monthly), `time` HH:MM di zona seri; akhir opsional `until` (YYYY-MM-DD) ATAU `count` (1–100), keduanya kosong = tanpa akhir.",
                    "example": {
                      "freq": "weekly",
                      "interval": 1,
                      "byWeekday": [
                        1,
                        4
                      ],
                      "time": "19:00",
                      "count": 8
                    }
                  },
                  "startsOn": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "Tanggal lokal kejadian pertama aturan (YYYY-MM-DD)",
                    "example": "2026-10-20"
                  },
                  "timezone": {
                    "description": "Zona aturan (jam & tanggal); bawaan zona workspace",
                    "example": "Asia/Jakarta",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  },
                  "versionMode": {
                    "default": "latest",
                    "description": "`latest` = tiap kejadian memakai isi carousel terbaru; `fixed` = versi dikunci saat seri dibuat",
                    "type": "string",
                    "enum": [
                      "latest",
                      "fixed"
                    ]
                  },
                  "captionVariation": {
                    "description": "Variasi caption AI (memakai Credit AI) untuk kejadian ke-2 dst.",
                    "type": "boolean"
                  },
                  "format": {
                    "description": "`carousel` (bawaan) atau `reels` = video MP4 9:16 dari carousel, dibuat saat posting dan diposting sebagai Reels (IG/FB), video (Threads), atau video TikTok. Reels butuh paket Pro, Ultimate, atau Agency.",
                    "type": "string",
                    "enum": [
                      "carousel",
                      "reels"
                    ]
                  },
                  "video": {
                    "description": "Opsi video, hanya dibaca untuk `format: \"reels\"` (kosong = bawaan: fit auto, 3 detik per slide, transisi pudar, tanpa animasi, tanpa musik). `animation`: `none` | `subtle` (teks masuk bertahap halus + foto zoom pelan) | `dynamic` (lebih cepat & terasa). `musicTrackId` butuh musik aktif.",
                    "example": {
                      "fit": "auto",
                      "secondsPerSlide": 3,
                      "transition": "fade",
                      "animation": "subtle",
                      "musicTrackId": null,
                      "musicVolume": 0.7
                    },
                    "type": "object",
                    "properties": {
                      "fit": {
                        "default": "auto",
                        "type": "string",
                        "enum": [
                          "auto",
                          "reflow",
                          "frame"
                        ]
                      },
                      "secondsPerSlide": {
                        "default": 3,
                        "type": "number",
                        "minimum": 2,
                        "maximum": 8,
                        "multipleOf": 0.5
                      },
                      "transition": {
                        "default": "fade",
                        "type": "string",
                        "enum": [
                          "none",
                          "fade",
                          "slide"
                        ]
                      },
                      "animation": {
                        "default": "none",
                        "type": "string",
                        "enum": [
                          "none",
                          "subtle",
                          "dynamic"
                        ]
                      },
                      "musicTrackId": {
                        "default": null,
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "musicVolume": {
                        "default": 0.7,
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      }
                    }
                  }
                },
                "required": [
                  "carouselId",
                  "platforms",
                  "rule",
                  "startsOn"
                ],
                "additionalProperties": false,
                "example": {
                  "carouselId": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22",
                  "platforms": [
                    "instagram"
                  ],
                  "rule": {
                    "freq": "weekly",
                    "interval": 1,
                    "byWeekday": [
                      1,
                      4
                    ],
                    "time": "19:00",
                    "count": 8
                  },
                  "startsOn": "2026-10-20",
                  "format": "reels"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Dibuat",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduleSeries"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listScheduleSeries",
        "tags": [
          "Series"
        ],
        "summary": "Daftar jadwal berulang",
        "description": "Seri workspace: aktif → dijeda → selesai → diakhiri, terbaru dulu (maks 200).\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/schedule-series \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedule-series', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Daftar jadwal berulang\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/schedule-series\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "carouselId",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
            }
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "paused",
                "ended",
                "canceled"
              ]
            }
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ScheduleSeries"
                      }
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/schedule-series/{id}": {
      "get": {
        "operationId": "getScheduleSeries",
        "tags": [
          "Series"
        ],
        "summary": "Status jadwal berulang",
        "description": "Aturan, status (`pausedReason` bila dijeda), posting berikutnya, jumlah kejadian mendatang & yang sudah terbit.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Status jadwal berulang\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduleSeries"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateScheduleSeries",
        "tags": [
          "Series"
        ],
        "summary": "Ubah jadwal berulang",
        "description": "Berlaku untuk kejadian berikutnya: kejadian mendatang yang belum diproses dibatalkan lalu dibuat ulang. `platforms` (+ `accounts`) mengganti akun; `captions`/`tiktok` tanpa `platforms` = akun yang sama; `refresh: true` = terapkan isi carousel terbaru. Seri selesai/diakhiri → 409.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X PATCH https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"rule\":{\"freq\":\"daily\",\"interval\":2,\"time\":\"08:30\"},\"format\":\"carousel\"}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'PATCH',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"rule\":{\"freq\":\"daily\",\"interval\":2,\"time\":\"08:30\"},\"format\":\"carousel\"}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Ubah jadwal berulang\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"PATCH\",\n        \"url\": \"https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"rule\\\":{\\\"freq\\\":\\\"daily\\\",\\\"interval\\\":2,\\\"time\\\":\\\"08:30\\\"},\\\"format\\\":\\\"carousel\\\"}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "platforms": {
                    "minItems": 1,
                    "maxItems": 4,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    }
                  },
                  "captions": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    },
                    "additionalProperties": {
                      "type": "string",
                      "maxLength": 5000,
                      "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                    }
                  },
                  "accounts": {
                    "description": "platform → accountId, array accountId, atau \"all\" (semua akun aktif). Wajib bila brand punya lebih dari satu akun aktif di platform itu (422 `AMBIGUOUS_ACCOUNT` + `candidates`). Daftar akun: GET /accounts.",
                    "example": {
                      "facebook": [
                        "5c2e9d1a-0b7f-4c3e-9a2d-1f8e6b4c7a90",
                        "6d3f0e2b-1c8a-4d4f-8b3e-2a9f7c5d8b01"
                      ]
                    },
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "enum": [
                        "instagram",
                        "facebook",
                        "threads",
                        "tiktok"
                      ]
                    },
                    "additionalProperties": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        {
                          "minItems": 1,
                          "maxItems": 10,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          }
                        },
                        {
                          "type": "string",
                          "const": "all"
                        }
                      ]
                    }
                  },
                  "tiktok": {
                    "description": "Wajib untuk TikTok. `privacyLevel` (PUBLIC_TO_EVERYONE | MUTUAL_FOLLOW_FRIENDS | FOLLOWER_OF_CREATOR | SELF_ONLY) dipilih user tanpa nilai bawaan dan harus salah satu `allowedPrivacyLevels` dari GET /accounts/{id}/tiktok-creator-info. `disableComment` (bawaan true = komentar mati), `disableDuet`/`disableStitch` (video Reels; bawaan true) — tidak boleh dinyalakan bila kreator mematikannya. Pengungkapan konten komersial: `brandOrganic` (promosi bisnis sendiri → label \"Promotional content\"), `brandContent` (pihak ketiga → \"Paid partnership\", tidak boleh SELF_ONLY). Foto saja: `title` ≤ 90, `autoAddMusic`. Dengan memposting, user menyetujui Music Usage Confirmation TikTok (+ Branded Content Policy untuk brandContent). Berlaku untuk semua akun TikTok jadwal.",
                    "type": "object",
                    "properties": {
                      "privacyLevel": {
                        "type": "string",
                        "enum": [
                          "PUBLIC_TO_EVERYONE",
                          "MUTUAL_FOLLOW_FRIENDS",
                          "FOLLOWER_OF_CREATOR",
                          "SELF_ONLY"
                        ]
                      },
                      "disableComment": {
                        "type": "boolean"
                      },
                      "brandContent": {
                        "type": "boolean"
                      },
                      "brandOrganic": {
                        "type": "boolean"
                      },
                      "autoAddMusic": {
                        "type": "boolean"
                      },
                      "title": {
                        "type": "string",
                        "maxLength": 90
                      },
                      "disableDuet": {
                        "type": "boolean"
                      },
                      "disableStitch": {
                        "type": "boolean"
                      }
                    },
                    "required": [
                      "privacyLevel"
                    ]
                  },
                  "rule": {
                    "type": "object",
                    "properties": {
                      "freq": {
                        "type": "string",
                        "enum": [
                          "daily",
                          "weekly",
                          "monthly"
                        ]
                      },
                      "interval": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 4
                      },
                      "byWeekday": {
                        "minItems": 1,
                        "maxItems": 7,
                        "type": "array",
                        "items": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 6
                        }
                      },
                      "byMonthDay": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      "time": {
                        "type": "string"
                      },
                      "until": {
                        "type": "string",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                      },
                      "count": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 100
                      }
                    },
                    "required": [
                      "freq",
                      "interval",
                      "time"
                    ],
                    "description": "`freq` daily|weekly|monthly, `interval` 1–4, `byWeekday` (0 = Minggu … 6 = Sabtu, wajib untuk weekly), `byMonthDay` (1–28 atau -1 = hari terakhir, wajib untuk monthly), `time` HH:MM di zona seri; akhir opsional `until` (YYYY-MM-DD) ATAU `count` (1–100), keduanya kosong = tanpa akhir.",
                    "example": {
                      "freq": "weekly",
                      "interval": 1,
                      "byWeekday": [
                        1,
                        4
                      ],
                      "time": "19:00",
                      "count": 8
                    }
                  },
                  "startsOn": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  "timezone": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  },
                  "versionMode": {
                    "type": "string",
                    "enum": [
                      "latest",
                      "fixed"
                    ]
                  },
                  "captionVariation": {
                    "type": "boolean"
                  },
                  "refresh": {
                    "type": "boolean",
                    "const": true
                  },
                  "format": {
                    "description": "`carousel` (bawaan) atau `reels` = video MP4 9:16 dari carousel, dibuat saat posting dan diposting sebagai Reels (IG/FB), video (Threads), atau video TikTok. Reels butuh paket Pro, Ultimate, atau Agency.",
                    "type": "string",
                    "enum": [
                      "carousel",
                      "reels"
                    ]
                  },
                  "video": {
                    "description": "Opsi video, hanya dibaca untuk `format: \"reels\"` (kosong = bawaan: fit auto, 3 detik per slide, transisi pudar, tanpa animasi, tanpa musik). `animation`: `none` | `subtle` (teks masuk bertahap halus + foto zoom pelan) | `dynamic` (lebih cepat & terasa). `musicTrackId` butuh musik aktif.",
                    "example": {
                      "fit": "auto",
                      "secondsPerSlide": 3,
                      "transition": "fade",
                      "animation": "subtle",
                      "musicTrackId": null,
                      "musicVolume": 0.7
                    },
                    "type": "object",
                    "properties": {
                      "fit": {
                        "default": "auto",
                        "type": "string",
                        "enum": [
                          "auto",
                          "reflow",
                          "frame"
                        ]
                      },
                      "secondsPerSlide": {
                        "default": 3,
                        "type": "number",
                        "minimum": 2,
                        "maximum": 8,
                        "multipleOf": 0.5
                      },
                      "transition": {
                        "default": "fade",
                        "type": "string",
                        "enum": [
                          "none",
                          "fade",
                          "slide"
                        ]
                      },
                      "animation": {
                        "default": "none",
                        "type": "string",
                        "enum": [
                          "none",
                          "subtle",
                          "dynamic"
                        ]
                      },
                      "musicTrackId": {
                        "default": null,
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "musicVolume": {
                        "default": 0.7,
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      }
                    }
                  }
                },
                "additionalProperties": false,
                "example": {
                  "rule": {
                    "freq": "daily",
                    "interval": 2,
                    "time": "08:30"
                  },
                  "format": "carousel"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduleSeries"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "endScheduleSeries",
        "tags": [
          "Series"
        ],
        "summary": "Akhiri jadwal berulang",
        "description": "Status `canceled`; kejadian mendatang yang belum diproses dibatalkan, yang sudah terbit tetap. Idempoten.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X DELETE https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'DELETE',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Akhiri jadwal berulang\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"DELETE\",\n        \"url\": \"https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduleSeries"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/schedule-series/{id}/pause": {
      "post": {
        "operationId": "pauseScheduleSeries",
        "tags": [
          "Series"
        ],
        "summary": "Jeda jadwal berulang",
        "description": "`paused` (alasan `manual`); kejadian mendatang yang belum diproses dibatalkan. Idempoten.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/pause \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/pause', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Jeda jadwal berulang\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/pause\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduleSeries"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/schedule-series/{id}/resume": {
      "post": {
        "operationId": "resumeScheduleSeries",
        "tags": [
          "Series"
        ],
        "summary": "Lanjutkan jadwal berulang",
        "description": "Validasi ulang (paket, langganan, carousel, akun, auto-post, approval) lalu kejadian berikutnya dijadwalkan; aturan sudah habis → `ended`. Idempoten.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/resume \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/resume', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Lanjutkan jadwal berulang\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/schedule-series/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/resume\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ScheduleSeries"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/brands": {
      "get": {
        "operationId": "listBrands",
        "tags": [
          "Brands"
        ],
        "summary": "Brand yang bisa diakses",
        "description": "Satu entri = satu workspace: workspace key, plus semua klien bila key milik agency. Pakai `id` sebagai `brandId` atau header `X-Workspace-Id`.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/brands \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/brands', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Brand yang bisa diakses\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/brands\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Brand"
                      }
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/accounts": {
      "get": {
        "operationId": "listAccounts",
        "tags": [
          "Accounts"
        ],
        "summary": "Akun sosial brand",
        "description": "Akun sosial terhubung satu brand (`brandId` / `X-Workspace-Id`): `id` untuk `accounts.<platform>` di POST /schedules, handle, nama (Facebook = nama Page), status koneksi, `canPost` + `blockedReason` (`ACCOUNT_DISCONNECTED` | `AUTOPOST_OFF` | `PLAN_REQUIRED`), batas caption per format. Tanpa token.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/accounts \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/accounts', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Akun sosial brand\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/accounts\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "brandId",
            "schema": {
              "description": "Workspace (dari GET /brands); bawaan = workspace key / X-Workspace-Id",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
            },
            "description": "Workspace (dari GET /brands); bawaan = workspace key / X-Workspace-Id"
          },
          {
            "in": "query",
            "name": "platform",
            "schema": {
              "type": "string",
              "enum": [
                "instagram",
                "facebook",
                "threads",
                "tiktok"
              ]
            }
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Account"
                      }
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/accounts/{id}/tiktok-creator-info": {
      "get": {
        "operationId": "getTiktokCreatorInfo",
        "tags": [
          "Accounts"
        ],
        "summary": "Info kreator TikTok",
        "description": "Info kreator TikTok terbaru (cache 60 detik) sebelum menjadwalkan: `allowedPrivacyLevels` (nilai sah `tiktok.privacyLevel`, tanpa bawaan — tanyakan ke user), komentar/Duet/Stitch yang dimatikan kreator (harus tetap mati), durasi video maks, `canPost`, dan kebijakan TikTok yang disetujui user saat posting (Content Sharing Guidelines). Bukan akun TikTok → 422.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/accounts/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/tiktok-creator-info \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/accounts/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/tiktok-creator-info', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Info kreator TikTok\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/accounts/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/tiktok-creator-info\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/TiktokCreatorInfo"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "60 request/menit per key, 10 generate bersamaan (`details.reason: concurrency`), atau batas harian; lihat `Retry-After`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Provider gagal setelah fallback; Credit AI sudah dikembalikan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/templates": {
      "get": {
        "operationId": "listTemplates",
        "tags": [
          "Templates"
        ],
        "summary": "Katalog template",
        "description": "Template yang boleh dipakai paket workspace (+ template privat agency).\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/templates \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/templates', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Katalog template\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/templates\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "family",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            }
          },
          {
            "in": "query",
            "name": "category",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 32
            }
          },
          {
            "in": "query",
            "name": "ratio",
            "schema": {
              "type": "string",
              "enum": [
                "4:5",
                "1:1",
                "9:16"
              ]
            }
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Template"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "nextCursor"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/ideas": {
      "get": {
        "operationId": "listIdeas",
        "tags": [
          "Ideas"
        ],
        "summary": "Ide konten terkini (tanpa Credit AI)",
        "description": "Berita terkurasi + momen jualan per niche. `id` bisa dipakai sebagai `source: {type: \"idea\", value: id}`.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/ideas \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/ideas', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Ide konten terkini (tanpa Credit AI)\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/ideas\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "niche",
            "schema": {
              "description": "Kategori ide (bawaan: niche brand)",
              "type": "string",
              "enum": [
                "umum",
                "kuliner",
                "fashion",
                "kecantikan",
                "jasa",
                "edukasi",
                "kesehatan",
                "keuangan",
                "properti",
                "teknologi",
                "travel",
                "otomotif",
                "anak",
                "religi",
                "event",
                "all"
              ]
            },
            "description": "Kategori ide (bawaan: niche brand)"
          },
          {
            "in": "query",
            "name": "country",
            "schema": {
              "type": "string",
              "enum": [
                "ID",
                "MY"
              ]
            }
          },
          {
            "in": "query",
            "name": "lang",
            "schema": {
              "type": "string",
              "enum": [
                "id",
                "en",
                "ms"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 10,
              "description": "Jumlah per halaman (maks 50)",
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "description": "Jumlah per halaman (maks 50)"
          },
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "Cursor opaque dari `meta.nextCursor`",
              "type": "string",
              "maxLength": 400
            },
            "description": "Cursor opaque dari `meta.nextCursor`"
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Idea"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "nextCursor"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/credits": {
      "get": {
        "operationId": "getCredits",
        "tags": [
          "Credits"
        ],
        "summary": "Saldo & riwayat Credit AI",
        "description": "Dompet paket + top-up, batas harian, kuota klien agency, riwayat ledger (cursor).\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/credits \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/credits', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Saldo & riwayat Credit AI\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/credits\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 20,
              "description": "Jumlah per halaman (maks 100)",
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            },
            "description": "Jumlah per halaman (maks 100)"
          },
          {
            "in": "query",
            "name": "cursor",
            "schema": {
              "description": "Cursor opaque dari `meta.nextCursor`",
              "type": "string",
              "maxLength": 400
            },
            "description": "Cursor opaque dari `meta.nextCursor`"
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Credits"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "nextCursor": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [
                        "nextCursor"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/batches": {
      "post": {
        "operationId": "createBatch",
        "tags": [
          "Batches"
        ],
        "summary": "Buat batch konten",
        "description": "Susun rencana dengan AI (memakai Credit AI, tarif diatur admin) dari brief, topik, link, atau ide; `run: true` + `confirmCredits: true` langsung menjalankan (Credit AI per item = slide + gambar AI sesuai tarif admin, dipotong per item saat item mulai). Tanpa `confirmCredits` → 422 dengan `details.credits`. Paket tanpa batch → 403.\n\nScope: `create` · Credit AI: rencana + per item (tarif admin) · `Idempotency-Key` wajib",
        "x-scope": "create",
        "x-credits": "rencana + per item (tarif admin)",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/batches \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Idempotency-Key: order-8812\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\":\"Konten Oktober\",\"sourceType\":\"topics\",\"source\":{\"topics\":[\"HPP kopi\",\"Promo gajian\",\"Cara menyeduh V60\"]},\"settings\":{\"slides\":5,\"ratio\":\"4:5\",\"lang\":\"id\",\"images\":true},\"run\":true,\"confirmCredits\":true}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/batches', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'order-8812' },\n  body: JSON.stringify({\"name\":\"Konten Oktober\",\"sourceType\":\"topics\",\"source\":{\"topics\":[\"HPP kopi\",\"Promo gajian\",\"Cara menyeduh V60\"]},\"settings\":{\"slides\":5,\"ratio\":\"4:5\",\"lang\":\"id\",\"images\":true},\"run\":true,\"confirmCredits\":true}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Buat batch konten\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/batches\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendHeaders\": true,\n        \"headerParameters\": {\n          \"parameters\": [\n            {\n              \"name\": \"Idempotency-Key\",\n              \"value\": \"={{ $json.id }}\"\n            }\n          ]\n        },\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"name\\\":\\\"Konten Oktober\\\",\\\"sourceType\\\":\\\"topics\\\",\\\"source\\\":{\\\"topics\\\":[\\\"HPP kopi\\\",\\\"Promo gajian\\\",\\\"Cara menyeduh V60\\\"]},\\\"settings\\\":{\\\"slides\\\":5,\\\"ratio\\\":\\\"4:5\\\",\\\"lang\\\":\\\"id\\\",\\\"images\\\":true},\\\"run\\\":true,\\\"confirmCredits\\\":true}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "schema": {
              "type": "string",
              "maxLength": 128,
              "description": "Wajib. Kunci unik per permintaan (≤ 128 karakter ASCII), disimpan 24 jam."
            },
            "required": true,
            "description": "Wajib. Kunci unik per permintaan (≤ 128 karakter ASCII), disimpan 24 jam."
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120,
                    "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                  },
                  "sourceType": {
                    "type": "string",
                    "enum": [
                      "brief",
                      "topics",
                      "links",
                      "ideas"
                    ]
                  },
                  "source": {
                    "type": "object",
                    "properties": {
                      "brief": {
                        "type": "string",
                        "minLength": 10,
                        "maxLength": 1500,
                        "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                      },
                      "period": {
                        "type": "object",
                        "properties": {
                          "start": {
                            "type": "string",
                            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                          },
                          "end": {
                            "type": "string",
                            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                          }
                        },
                        "required": [
                          "start",
                          "end"
                        ]
                      },
                      "topics": {
                        "minItems": 1,
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 3,
                          "maxLength": 400,
                          "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                        }
                      },
                      "links": {
                        "minItems": 1,
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 2048
                        }
                      },
                      "ideaIds": {
                        "minItems": 1,
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        }
                      }
                    },
                    "additionalProperties": false
                  },
                  "settings": {
                    "type": "object",
                    "properties": {
                      "slides": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 12
                      },
                      "ratio": {
                        "type": "string",
                        "enum": [
                          "4:5",
                          "1:1",
                          "9:16"
                        ]
                      },
                      "lang": {
                        "type": "string",
                        "enum": [
                          "id",
                          "en",
                          "ms"
                        ]
                      },
                      "tone": {
                        "type": "string",
                        "enum": [
                          "santai",
                          "profesional",
                          "edukatif",
                          "storytelling",
                          "jualan",
                          "lucu"
                        ]
                      },
                      "images": {
                        "type": "boolean"
                      },
                      "templateId": {
                        "type": "string",
                        "pattern": "^[a-z0-9][a-z0-9-]{0,63}$"
                      },
                      "count": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 30
                      }
                    },
                    "required": [
                      "slides",
                      "ratio",
                      "lang"
                    ],
                    "additionalProperties": false
                  },
                  "run": {
                    "default": false,
                    "type": "boolean"
                  },
                  "confirmCredits": {
                    "type": "boolean"
                  },
                  "brandId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
                  }
                },
                "required": [
                  "name",
                  "sourceType",
                  "source",
                  "settings"
                ],
                "additionalProperties": false,
                "example": {
                  "name": "Konten Oktober",
                  "sourceType": "topics",
                  "source": {
                    "topics": [
                      "HPP kopi",
                      "Promo gajian",
                      "Cara menyeduh V60"
                    ]
                  },
                  "settings": {
                    "slides": 5,
                    "ratio": "4:5",
                    "lang": "id",
                    "images": true
                  },
                  "run": true,
                  "confirmCredits": true
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Diterima (diproses async)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/BatchCreated"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Credit AI kurang (`details.required`, `details.available`) atau kuota klien habis (`details.reason: client_quota`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key dipakai ulang dengan body berbeda / masih diproses, atau status/versi bentrok",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "60 request/menit per key, 10 generate bersamaan (`details.reason: concurrency`), atau batas harian; lihat `Retry-After`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/batches/{id}": {
      "get": {
        "operationId": "getBatch",
        "tags": [
          "Batches"
        ],
        "summary": "Status batch",
        "description": "Progres dan status per item (`carouselId` setelah item dibuat).\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/batches/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/batches/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Status batch\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/batches/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Batch"
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks": {
      "post": {
        "operationId": "createWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Daftarkan endpoint webhook",
        "description": "Posto mengirim POST JSON bertanda tangan (`X-Posto-Signature: v1=<HMAC-SHA256 hex>` atas `{X-Posto-Timestamp}.{raw body}`) untuk event yang dipilih. `secret` (whsec_…) hanya tampil di respons ini. URL wajib https dan alamat publik (IP privat/loopback ditolak setelah resolusi DNS); redirect tidak diikuti. Sukses = 2xx dalam 10 detik; gagal diulang 1m, 5m, 30m, 2h, 8h, 24h; gagal berturut 3 hari → endpoint dimatikan + email ke pemilik. Maksimal 10 endpoint per workspace.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/webhooks \\\n  -H \"Authorization: Bearer $POSTO_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\":\"https://n8n.agensi.id/webhook/posto\",\"events\":[\"carousel.ready\",\"post.published\",\"post.failed\",\"credits.low\"],\"description\":\"n8n produksi\"}'"
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/webhooks', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}`, 'Content-Type': 'application/json' },\n  body: JSON.stringify({\"url\":\"https://n8n.agensi.id/webhook/posto\",\"events\":[\"carousel.ready\",\"post.published\",\"post.failed\",\"credits.low\"],\"description\":\"n8n produksi\"}),\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Daftarkan endpoint webhook\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/webhooks\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\",\n        \"sendBody\": true,\n        \"specifyBody\": \"json\",\n        \"jsonBody\": \"{\\\"url\\\":\\\"https://n8n.agensi.id/webhook/posto\\\",\\\"events\\\":[\\\"carousel.ready\\\",\\\"post.published\\\",\\\"post.failed\\\",\\\"credits.low\\\"],\\\"description\\\":\\\"n8n produksi\\\"}\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "description": "Wajib https dan alamat publik (IP privat/loopback ditolak)",
                    "example": "https://n8n.agensi.id/webhook/posto",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2048
                  },
                  "events": {
                    "minItems": 1,
                    "maxItems": 9,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "carousel.ready",
                        "carousel.failed",
                        "image.ready",
                        "post.published",
                        "post.failed",
                        "credits.low",
                        "approval.decided",
                        "series.paused",
                        "series.ended"
                      ]
                    }
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 120,
                        "pattern": "^[^\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]*$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "brandId": {
                    "description": "Workspace tujuan; bawaan = workspace key / X-Workspace-Id",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "example": "7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22"
                  }
                },
                "required": [
                  "url",
                  "events"
                ],
                "additionalProperties": false,
                "example": {
                  "url": "https://n8n.agensi.id/webhook/posto",
                  "events": [
                    "carousel.ready",
                    "post.published",
                    "post.failed",
                    "credits.low"
                  ],
                  "description": "n8n produksi"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Dibuat",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "url": {
                          "type": "string"
                        },
                        "description": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "carousel.ready",
                              "carousel.failed",
                              "image.ready",
                              "post.published",
                              "post.failed",
                              "credits.low",
                              "approval.decided",
                              "series.paused",
                              "series.ended"
                            ]
                          }
                        },
                        "active": {
                          "type": "boolean",
                          "description": "false = dimatikan (otomatis setelah gagal 3 hari berturut)"
                        },
                        "failureCount": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Kiriman berturut gagal setelah semua retry"
                        },
                        "disabledAt": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "previousSecretExpiresAt": {
                          "description": "Rahasia lama masih ikut ditandatangani sampai waktu ini (24 jam setelah rotasi)",
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "createdAt": {
                          "type": "string"
                        },
                        "secret": {
                          "type": "string",
                          "description": "whsec_… — tampil SEKALI; dipakai memverifikasi X-Posto-Signature"
                        }
                      },
                      "required": [
                        "id",
                        "url",
                        "description",
                        "events",
                        "active",
                        "failureCount",
                        "disabledAt",
                        "previousSecretExpiresAt",
                        "createdAt",
                        "secret"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "listWebhooks",
        "tags": [
          "Webhooks"
        ],
        "summary": "Daftar endpoint webhook",
        "description": "Endpoint workspace (tanpa rahasia), status aktif, dan hitungan gagal berturut.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/webhooks \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/webhooks', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Daftar endpoint webhook\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/webhooks\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Webhook"
                      }
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{id}": {
      "delete": {
        "operationId": "deleteWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Hapus endpoint webhook",
        "description": "Endpoint dan riwayat kirimannya dihapus; kiriman yang masih tertunda dibatalkan.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X DELETE https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22 \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22', {\n  method: 'DELETE',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Hapus endpoint webhook\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"DELETE\",\n        \"url\": \"https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "deleted": {
                          "type": "boolean",
                          "const": true
                        }
                      },
                      "required": [
                        "id",
                        "deleted"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "post": {
        "operationId": "testWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Kirim event ping",
        "description": "Mengantrekan event `ping` (data `{}`) — satu percobaan tanpa retry, juga ke endpoint yang sedang mati. Lihat hasilnya di GET /webhooks/{id}/deliveries.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/test \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/test', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Kirim event ping\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/test\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "202": {
            "description": "Diterima (diproses async)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "deliveryId": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "eventId": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        }
                      },
                      "required": [
                        "deliveryId",
                        "eventId"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "tags": [
          "Webhooks"
        ],
        "summary": "Riwayat kiriman",
        "description": "Kiriman terbaru (bawaan 20): status `delivered | pending | failed`, percobaan ke-n, status HTTP & potongan balasan endpoint.\n\nScope: `read` · Credit AI: 0",
        "x-scope": "read",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X GET https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/deliveries \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/deliveries', {\n  method: 'GET',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Riwayat kiriman\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"GET\",\n        \"url\": \"https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/deliveries\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "default": 20,
              "description": "Jumlah kiriman terbaru (maks 50)",
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "description": "Jumlah kiriman terbaru (maks 50)"
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validasi gagal (`details.issues[]`) atau ditolak moderasi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{id}/rotate-secret": {
      "post": {
        "operationId": "rotateWebhookSecret",
        "tags": [
          "Webhooks"
        ],
        "summary": "Rotasi rahasia",
        "description": "Rahasia baru tampil sekali. Selama 24 jam header memuat dua tanda tangan (`v1=<baru>,v1=<lama>`) supaya penerima bisa berganti tanpa jeda.\n\nScope: `schedule` · Credit AI: 0",
        "x-scope": "schedule",
        "x-credits": "0",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl -X POST https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/rotate-secret \\\n  -H \"Authorization: Bearer $POSTO_KEY\""
          },
          {
            "lang": "JavaScript",
            "label": "Node (fetch)",
            "source": "const res = await fetch('https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/rotate-secret', {\n  method: 'POST',\n  headers: { Authorization: `Bearer ${process.env.POSTO_KEY}` },\n})\nconst json = await res.json()\nif (!json.ok) throw new Error(json.error.message)\nconsole.log(json.data)"
          },
          {
            "lang": "JSON",
            "label": "n8n (HTTP Request)",
            "source": "{\n  \"nodes\": [\n    {\n      \"name\": \"Posto: Rotasi rahasia\",\n      \"type\": \"n8n-nodes-base.httpRequest\",\n      \"typeVersion\": 4.2,\n      \"parameters\": {\n        \"method\": \"POST\",\n        \"url\": \"https://posto.id/api/v1/webhooks/7d3f9c2e-5b1a-4e8f-9a61-2c4b8e0f1d22/rotate-secret\",\n        \"authentication\": \"genericCredentialType\",\n        \"genericAuthType\": \"httpHeaderAuth\"\n      }\n    }\n  ]\n}"
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "required": true
          },
          {
            "in": "header",
            "name": "X-Workspace-Id",
            "schema": {
              "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key.",
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            },
            "description": "Key agency: workspace klien tujuan (dari GET /brands). Bawaan = workspace key."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "url": {
                          "type": "string"
                        },
                        "description": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "carousel.ready",
                              "carousel.failed",
                              "image.ready",
                              "post.published",
                              "post.failed",
                              "credits.low",
                              "approval.decided",
                              "series.paused",
                              "series.ended"
                            ]
                          }
                        },
                        "active": {
                          "type": "boolean",
                          "description": "false = dimatikan (otomatis setelah gagal 3 hari berturut)"
                        },
                        "failureCount": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Kiriman berturut gagal setelah semua retry"
                        },
                        "disabledAt": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "previousSecretExpiresAt": {
                          "description": "Rahasia lama masih ikut ditandatangani sampai waktu ini (24 jam setelah rotasi)",
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "createdAt": {
                          "type": "string"
                        },
                        "secret": {
                          "type": "string",
                          "description": "whsec_… — tampil SEKALI; dipakai memverifikasi X-Posto-Signature"
                        }
                      },
                      "required": [
                        "id",
                        "url",
                        "description",
                        "events",
                        "active",
                        "failureCount",
                        "disabledAt",
                        "previousSecretExpiresAt",
                        "createdAt",
                        "secret"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "API key tidak ada / tidak valid / dicabut (header `WWW-Authenticate`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Scope key kurang (`details.requiredScope`), paket tanpa API (`details.reason: plan`), fitur belum dibuka",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Tidak ada atau milik workspace lain (tidak dibedakan)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "ping": {
      "post": {
        "operationId": "webhook_ping",
        "tags": [
          "Webhooks"
        ],
        "summary": "ping",
        "description": "Tes manual (tombol \"Kirim ping\" / POST /webhooks/{id}/test).",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "ping"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {}
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "carousel.ready": {
      "post": {
        "operationId": "webhook_carousel_ready",
        "tags": [
          "Webhooks"
        ],
        "summary": "carousel.ready",
        "description": "Job generate selesai (sukses). Dikirim ke `webhookUrl` job bila diisi saat POST /carousels.",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "carousel.ready"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "status": {
                        "type": "string",
                        "const": "ready"
                      },
                      "title": {
                        "type": "string"
                      },
                      "slidesCount": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      "credits": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991,
                        "description": "Credit AI bersih (dipotong − dikembalikan)"
                      },
                      "warnings": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    },
                    "required": [
                      "id",
                      "status",
                      "title",
                      "slidesCount",
                      "credits",
                      "warnings"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "carousel.failed": {
      "post": {
        "operationId": "webhook_carousel_failed",
        "tags": [
          "Webhooks"
        ],
        "summary": "carousel.failed",
        "description": "Job generate gagal; Credit AI sudah dikembalikan.",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "carousel.failed"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "error": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "message"
                        ]
                      },
                      "credits": {
                        "type": "object",
                        "properties": {
                          "refunded": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          }
                        },
                        "required": [
                          "refunded"
                        ]
                      }
                    },
                    "required": [
                      "id",
                      "error",
                      "credits"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "image.ready": {
      "post": {
        "operationId": "webhook_image_ready",
        "tags": [
          "Webhooks"
        ],
        "summary": "image.ready",
        "description": "Foto AI satu slide selesai (POST /carousels/{id}/images atau studio).",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "image.ready"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "carouselId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "slideId": {
                        "type": "string"
                      },
                      "tier": {
                        "type": "string",
                        "enum": [
                          "standard",
                          "high"
                        ]
                      },
                      "mediaId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      }
                    },
                    "required": [
                      "carouselId",
                      "slideId",
                      "tier",
                      "mediaId"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "post.published": {
      "post": {
        "operationId": "webhook_post_published",
        "tags": [
          "Webhooks"
        ],
        "summary": "post.published",
        "description": "Satu target jadwal terbit.",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "post.published"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "scheduleId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "carouselId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "platform": {
                        "type": "string",
                        "enum": [
                          "instagram",
                          "facebook",
                          "threads",
                          "tiktok"
                        ]
                      },
                      "externalId": {
                        "type": "string"
                      },
                      "permalink": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "publishedAt": {
                        "type": "string"
                      },
                      "format": {
                        "type": "string",
                        "enum": [
                          "carousel",
                          "reels"
                        ],
                        "description": "M7-01: `reels` = diposting sebagai video"
                      },
                      "seriesId": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          },
                          {
                            "type": "null"
                          }
                        ],
                        "description": "M7-01: seri jadwal berulang asal; null = jadwal biasa"
                      }
                    },
                    "required": [
                      "scheduleId",
                      "carouselId",
                      "platform",
                      "externalId",
                      "permalink",
                      "publishedAt",
                      "format",
                      "seriesId"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "post.failed": {
      "post": {
        "operationId": "webhook_post_failed",
        "tags": [
          "Webhooks"
        ],
        "summary": "post.failed",
        "description": "Satu target jadwal gagal setelah retry habis (atau dibatalkan sistem).",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "post.failed"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "scheduleId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "carouselId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "platform": {
                        "type": "string",
                        "enum": [
                          "instagram",
                          "facebook",
                          "threads",
                          "tiktok"
                        ]
                      },
                      "error": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "message"
                        ]
                      },
                      "attempts": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      "format": {
                        "type": "string",
                        "enum": [
                          "carousel",
                          "reels"
                        ]
                      },
                      "seriesId": {
                        "anyOf": [
                          {
                            "type": "string",
                            "format": "uuid",
                            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    },
                    "required": [
                      "scheduleId",
                      "carouselId",
                      "platform",
                      "error",
                      "attempts",
                      "format",
                      "seriesId"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "credits.low": {
      "post": {
        "operationId": "webhook_credits_low",
        "tags": [
          "Webhooks"
        ],
        "summary": "credits.low",
        "description": "Total Credit AI < 10% jatah paket — sekali per periode.",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "credits.low"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "total": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      "threshold": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991,
                        "description": "10% jatah Credit AI paket"
                      },
                      "planCredits": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      }
                    },
                    "required": [
                      "total",
                      "threshold",
                      "planCredits"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "approval.decided": {
      "post": {
        "operationId": "webhook_approval_decided",
        "tags": [
          "Webhooks"
        ],
        "summary": "approval.decided",
        "description": "Klien menyetujui / minta revisi di halaman review.",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "approval.decided"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "carouselId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "decision": {
                        "type": "string",
                        "enum": [
                          "approved",
                          "changes_requested"
                        ]
                      },
                      "note": {
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    },
                    "required": [
                      "carouselId",
                      "decision",
                      "note"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "series.paused": {
      "post": {
        "operationId": "webhook_series_paused",
        "tags": [
          "Webhooks"
        ],
        "summary": "series.paused",
        "description": "Jadwal berulang dijeda — otomatis (akun terputus, langganan, approval, carousel dihapus, aturan platform) atau manual (`reason: manual`).",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "series.paused"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "seriesId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "carouselId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "reason": {
                        "type": "string",
                        "enum": [
                          "account_inactive",
                          "subscription",
                          "approval",
                          "carousel_missing",
                          "platform_gate",
                          "manual"
                        ]
                      },
                      "pausedAt": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "seriesId",
                      "carouselId",
                      "reason",
                      "pausedAt"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    },
    "series.ended": {
      "post": {
        "operationId": "webhook_series_ended",
        "tags": [
          "Webhooks"
        ],
        "summary": "series.ended",
        "description": "Jadwal berulang berakhir: aturan habis (`ended`) atau diakhiri user/API (`canceled`). Sekali per seri.",
        "parameters": [
          {
            "in": "header",
            "name": "X-Posto-Event",
            "schema": {
              "type": "string",
              "description": "Nama event"
            },
            "required": true,
            "description": "Nama event"
          },
          {
            "in": "header",
            "name": "X-Posto-Delivery",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "Id kiriman (sama di setiap retry)"
            },
            "required": true,
            "description": "Id kiriman (sama di setiap retry)"
          },
          {
            "in": "header",
            "name": "X-Posto-Timestamp",
            "schema": {
              "type": "string",
              "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
            },
            "required": true,
            "description": "Detik Unix; tolak bila selisih > 300 detik (replay)"
          },
          {
            "in": "header",
            "name": "X-Posto-Signature",
            "schema": {
              "type": "string",
              "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
            },
            "required": true,
            "description": "`v1=` + hex(HMAC_SHA256(secret, \"{timestamp}.{raw body}\")); dua nilai dipisah koma selama 24 jam setelah rotasi"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                    "description": "Id event — abaikan duplikat"
                  },
                  "type": {
                    "type": "string",
                    "const": "series.ended"
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "apiVersion": {
                    "type": "string",
                    "const": "v1"
                  },
                  "data": {
                    "type": "object",
                    "properties": {
                      "seriesId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "carouselId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "ended",
                          "canceled"
                        ],
                        "description": "`ended` = aturan habis; `canceled` = diakhiri user/API"
                      },
                      "occurrencesCreated": {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      "endedAt": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "seriesId",
                      "carouselId",
                      "status",
                      "occurrencesCreated",
                      "endedAt"
                    ]
                  }
                },
                "required": [
                  "id",
                  "type",
                  "createdAt",
                  "workspaceId",
                  "apiVersion",
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Balas 2xx dalam 10 detik; proses berat secara async"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Slide": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "cover",
              "point",
              "outro",
              "flyer"
            ]
          },
          "label": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "cta": {
            "type": "string"
          },
          "imageMediaId": {
            "type": "string"
          },
          "imageUrl": {
            "description": "URL bertanda tangan / CDN, berlaku ±1 jam",
            "type": "string"
          },
          "imageFailed": {
            "type": "boolean"
          },
          "visualMode": {
            "type": "string",
            "enum": [
              "photo",
              "illustration",
              "icon",
              "type"
            ]
          },
          "layout": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {}
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "image",
                  "video"
                ]
              },
              "durationSec": {
                "description": "Video: durasi potongan (detik)",
                "type": "number"
              },
              "sound": {
                "description": "Video: suara ikut",
                "type": "boolean"
              }
            },
            "required": [
              "type"
            ],
            "description": "Jenis media slide (PR-C). `video` = slide video studio (klip unggahan + teks template; diposting sebagai MP4 di carousel Instagram/Threads; Facebook & TikTok menolak carousel campuran)."
          },
          "video": {
            "description": "Slide video: klip unggahan (mode full).",
            "type": "object",
            "properties": {
              "mediaId": {
                "type": "string"
              },
              "posterMediaId": {
                "type": "string"
              },
              "edit": {
                "type": "object",
                "properties": {
                  "trimStartSec": {
                    "type": "number"
                  },
                  "trimEndSec": {
                    "type": "number"
                  },
                  "muted": {
                    "type": "boolean"
                  },
                  "coverSec": {
                    "type": "number"
                  }
                }
              },
              "durationSec": {
                "type": "number"
              },
              "width": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "height": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "hasAudio": {
                "type": "boolean"
              }
            },
            "required": [
              "mediaId",
              "posterMediaId",
              "durationSec",
              "width",
              "height",
              "hasAudio"
            ]
          }
        },
        "required": [
          "id",
          "role",
          "title",
          "media"
        ],
        "additionalProperties": {}
      },
      "Carousel": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "ready",
              "failed"
            ]
          },
          "workflowStatus": {
            "type": "string",
            "description": "carousels.status: draft | in_review | approved | scheduled | …"
          },
          "progress": {
            "description": "Hanya saat processing",
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "title": {
            "type": "string"
          },
          "ratio": {
            "type": "string",
            "enum": [
              "4:5",
              "1:1",
              "9:16"
            ]
          },
          "lang": {
            "type": "string"
          },
          "templateId": {
            "type": "string"
          },
          "templateVersion": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "brandId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "slides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Slide"
            }
          },
          "hookOptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "caption": {
            "type": "string"
          },
          "hashtags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "credits": {
            "type": "object",
            "properties": {
              "spent": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "refunded": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              }
            },
            "required": [
              "spent",
              "refunded"
            ]
          },
          "requestedSlides": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Jumlah slide yang diminta saat dibuat (ADR 0081)"
          },
          "slideCount": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Jumlah slide yang dibuat (tanpa flyer penutup); saat processing/failed = diminta"
          },
          "slidesReduced": {
            "description": "Ada bila slide dikurangi (materi tipis / slide tanpa fakta dibuang); Credit AI selisihnya sudah direfund (`credits.refunded`).",
            "type": "object",
            "properties": {
              "requested": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "made": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "reason": {
                "type": "string",
                "enum": [
                  "THIN_SOURCE",
                  "QUALITY_REVIEW"
                ]
              }
            },
            "required": [
              "requested",
              "made",
              "reason"
            ]
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "reason": {
                "description": "Kode mesin UPPER_SNAKE, mis. SLIDES_REDUCED, SOURCE_TOO_THIN",
                "type": "string"
              },
              "fix": {
                "description": "Langkah perbaikan singkat (bahasa = Accept-Language)",
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          },
          "studioUrl": {
            "type": "string"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "status",
          "workflowStatus",
          "title",
          "ratio",
          "lang",
          "templateId",
          "templateVersion",
          "brandId",
          "slides",
          "hookOptions",
          "caption",
          "hashtags",
          "credits",
          "requestedSlides",
          "slideCount",
          "warnings",
          "studioUrl",
          "createdAt",
          "updatedAt"
        ]
      },
      "CarouselSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "processing",
              "ready",
              "failed"
            ]
          },
          "workflowStatus": {
            "type": "string",
            "description": "carousels.status: draft | in_review | approved | scheduled | …"
          },
          "title": {
            "type": "string"
          },
          "ratio": {
            "type": "string",
            "enum": [
              "4:5",
              "1:1",
              "9:16"
            ]
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "status",
          "workflowStatus",
          "title",
          "ratio",
          "createdAt",
          "updatedAt"
        ]
      },
      "Schedule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "carouselId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              {
                "type": "null"
              }
            ],
            "description": "null = posting media sendiri (`kind: \"upload\"`, PR-B)"
          },
          "carouselTitle": {
            "type": "string",
            "description": "Judul carousel (MCP-A, aditif); posting media sendiri: potongan caption"
          },
          "kind": {
            "type": "string",
            "enum": [
              "carousel",
              "upload",
              "thread"
            ],
            "description": "PR-B (aditif): `upload` = posting media sendiri. UT-4 (aditif): `thread` = utas Threads (dibuat dari web; hanya waktu yang bisa diubah lewat API)"
          },
          "media": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "mediaId": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    },
                    "type": {
                      "type": "string",
                      "enum": [
                        "image",
                        "video"
                      ]
                    },
                    "durationSec": {
                      "description": "Video: durasi potongan (detik)",
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "trimStartSec": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "trimEndSec": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "muted": {
                      "type": "boolean"
                    },
                    "coverSec": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "missing": {
                      "type": "boolean",
                      "description": "Media sudah dihapus (posting akan gagal MEDIA_MISSING)"
                    }
                  },
                  "required": [
                    "mediaId",
                    "type",
                    "durationSec",
                    "trimStartSec",
                    "trimEndSec",
                    "muted",
                    "coverSec",
                    "missing"
                  ]
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Item posting media sendiri; null = carousel"
          },
          "thread": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "postThreadId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "postCount": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "title": {
                    "type": "string"
                  }
                },
                "required": [
                  "postThreadId",
                  "postCount",
                  "title"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Utas Threads (UT-4, aditif): id utas, jumlah posting, judul internal; null = bukan utas"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "rendering",
              "publishing",
              "published",
              "failed",
              "canceled"
            ]
          },
          "paused": {
            "type": "boolean",
            "description": "Dijeda karena paket berakhir (aditif): `status` tetap `canceled` dan target ber-`error.code` `SUBSCRIPTION_PAUSED`. Pulih otomatis menjadi `scheduled` saat paket dibayar bila `publishAt` masih di depan; yang waktunya sudah lewat menjadi `failed` dengan `SUBSCRIPTION_MISSED` (tidak diposting terlambat; jadwalkan ulang)"
          },
          "publishAt": {
            "type": "string"
          },
          "format": {
            "type": "string",
            "enum": [
              "carousel",
              "reels"
            ]
          },
          "video": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "fit": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "reflow",
                      "frame"
                    ]
                  },
                  "secondsPerSlide": {
                    "type": "number"
                  },
                  "transition": {
                    "type": "string",
                    "enum": [
                      "none",
                      "fade",
                      "slide"
                    ]
                  },
                  "animation": {
                    "description": "Animasi isi slide (M7-04); jadwal lama tanpa kunci ini = `none`",
                    "type": "string",
                    "enum": [
                      "none",
                      "subtle",
                      "dynamic"
                    ]
                  },
                  "musicTrackId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "musicVolume": {
                    "type": "number"
                  }
                },
                "required": [
                  "fit",
                  "secondsPerSlide",
                  "transition",
                  "musicTrackId",
                  "musicVolume"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Opsi video (hanya `reels`)"
          },
          "videoDurationSec": {
            "description": "Perkiraan durasi video (detik); null = carousel",
            "type": [
              "number",
              "null"
            ]
          },
          "seriesId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              {
                "type": "null"
              }
            ],
            "description": "Seri jadwal berulang asal; null = jadwal biasa"
          },
          "seriesSeq": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "targets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "platform": {
                  "type": "string",
                  "enum": [
                    "instagram",
                    "facebook",
                    "threads",
                    "tiktok"
                  ]
                },
                "accountId": {
                  "type": "string",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                },
                "handle": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "scheduled",
                    "rendering",
                    "publishing",
                    "published",
                    "failed",
                    "canceled"
                  ]
                },
                "externalId": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "permalink": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "publishedAt": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "error": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "attempts": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "caption": {
                  "type": "string",
                  "description": "Caption yang akan/sudah diposting ke akun ini (MCP-A, aditif)"
                },
                "format": {
                  "type": "string",
                  "enum": [
                    "carousel",
                    "reels"
                  ]
                },
                "reelsStep": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "video",
                        "upload",
                        "processing",
                        "published"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Progres Reels: video → upload → processing → published; null = carousel / belum mulai"
                }
              },
              "required": [
                "platform",
                "accountId",
                "handle",
                "status",
                "externalId",
                "permalink",
                "publishedAt",
                "error",
                "attempts",
                "caption",
                "format",
                "reelsStep"
              ]
            }
          },
          "calendarUrl": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "carouselId",
          "carouselTitle",
          "kind",
          "media",
          "thread",
          "status",
          "paused",
          "publishAt",
          "format",
          "video",
          "videoDurationSec",
          "seriesId",
          "seriesSeq",
          "targets",
          "calendarUrl"
        ]
      },
      "ScheduleCreated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "carouselId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              {
                "type": "null"
              }
            ],
            "description": "null = posting media sendiri (`kind: \"upload\"`, PR-B)"
          },
          "carouselTitle": {
            "type": "string",
            "description": "Judul carousel (MCP-A, aditif); posting media sendiri: potongan caption"
          },
          "kind": {
            "type": "string",
            "enum": [
              "carousel",
              "upload",
              "thread"
            ],
            "description": "PR-B (aditif): `upload` = posting media sendiri. UT-4 (aditif): `thread` = utas Threads (dibuat dari web; hanya waktu yang bisa diubah lewat API)"
          },
          "media": {
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "mediaId": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    },
                    "type": {
                      "type": "string",
                      "enum": [
                        "image",
                        "video"
                      ]
                    },
                    "durationSec": {
                      "description": "Video: durasi potongan (detik)",
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "trimStartSec": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "trimEndSec": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "muted": {
                      "type": "boolean"
                    },
                    "coverSec": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "missing": {
                      "type": "boolean",
                      "description": "Media sudah dihapus (posting akan gagal MEDIA_MISSING)"
                    }
                  },
                  "required": [
                    "mediaId",
                    "type",
                    "durationSec",
                    "trimStartSec",
                    "trimEndSec",
                    "muted",
                    "coverSec",
                    "missing"
                  ]
                }
              },
              {
                "type": "null"
              }
            ],
            "description": "Item posting media sendiri; null = carousel"
          },
          "thread": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "postThreadId": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "postCount": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "title": {
                    "type": "string"
                  }
                },
                "required": [
                  "postThreadId",
                  "postCount",
                  "title"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Utas Threads (UT-4, aditif): id utas, jumlah posting, judul internal; null = bukan utas"
          },
          "status": {
            "type": "string",
            "enum": [
              "scheduled",
              "rendering",
              "publishing",
              "published",
              "failed",
              "canceled"
            ]
          },
          "paused": {
            "type": "boolean",
            "description": "Dijeda karena paket berakhir (aditif): `status` tetap `canceled` dan target ber-`error.code` `SUBSCRIPTION_PAUSED`. Pulih otomatis menjadi `scheduled` saat paket dibayar bila `publishAt` masih di depan; yang waktunya sudah lewat menjadi `failed` dengan `SUBSCRIPTION_MISSED` (tidak diposting terlambat; jadwalkan ulang)"
          },
          "publishAt": {
            "type": "string"
          },
          "format": {
            "type": "string",
            "enum": [
              "carousel",
              "reels"
            ]
          },
          "video": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "fit": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "reflow",
                      "frame"
                    ]
                  },
                  "secondsPerSlide": {
                    "type": "number"
                  },
                  "transition": {
                    "type": "string",
                    "enum": [
                      "none",
                      "fade",
                      "slide"
                    ]
                  },
                  "animation": {
                    "description": "Animasi isi slide (M7-04); jadwal lama tanpa kunci ini = `none`",
                    "type": "string",
                    "enum": [
                      "none",
                      "subtle",
                      "dynamic"
                    ]
                  },
                  "musicTrackId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "musicVolume": {
                    "type": "number"
                  }
                },
                "required": [
                  "fit",
                  "secondsPerSlide",
                  "transition",
                  "musicTrackId",
                  "musicVolume"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Opsi video (hanya `reels`)"
          },
          "videoDurationSec": {
            "description": "Perkiraan durasi video (detik); null = carousel",
            "type": [
              "number",
              "null"
            ]
          },
          "seriesId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              {
                "type": "null"
              }
            ],
            "description": "Seri jadwal berulang asal; null = jadwal biasa"
          },
          "seriesSeq": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "targets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "platform": {
                  "type": "string",
                  "enum": [
                    "instagram",
                    "facebook",
                    "threads",
                    "tiktok"
                  ]
                },
                "accountId": {
                  "type": "string",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                },
                "handle": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "scheduled",
                    "rendering",
                    "publishing",
                    "published",
                    "failed",
                    "canceled"
                  ]
                },
                "externalId": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "permalink": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "publishedAt": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "error": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "attempts": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "caption": {
                  "type": "string",
                  "description": "Caption yang akan/sudah diposting ke akun ini (MCP-A, aditif)"
                },
                "format": {
                  "type": "string",
                  "enum": [
                    "carousel",
                    "reels"
                  ]
                },
                "reelsStep": {
                  "anyOf": [
                    {
                      "type": "string",
                      "enum": [
                        "video",
                        "upload",
                        "processing",
                        "published"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "Progres Reels: video → upload → processing → published; null = carousel / belum mulai"
                }
              },
              "required": [
                "platform",
                "accountId",
                "handle",
                "status",
                "externalId",
                "permalink",
                "publishedAt",
                "error",
                "attempts",
                "caption",
                "format",
                "reelsStep"
              ]
            }
          },
          "calendarUrl": {
            "type": "string"
          },
          "publishNow": {
            "type": "boolean",
            "description": "Jadwal langsung diproses (`publishNow: true`)"
          },
          "skipped": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "platform": {
                  "type": "string",
                  "enum": [
                    "instagram",
                    "facebook",
                    "threads",
                    "tiktok"
                  ]
                },
                "accountId": {
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "handle": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "issues": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "reason": {
                        "type": "string",
                        "description": "Alasan mesin UPPER_SNAKE, mis. AMBIGUOUS_ACCOUNT, CAPTION_TOO_LONG"
                      },
                      "path": {
                        "type": "string",
                        "description": "Field yang perlu diubah, mis. `accounts.facebook`, `captions.threads`"
                      },
                      "message": {
                        "type": "string"
                      },
                      "fix": {
                        "type": "string",
                        "description": "Langkah perbaikan (bahasa request)"
                      },
                      "platform": {
                        "type": "string",
                        "enum": [
                          "instagram",
                          "facebook",
                          "threads",
                          "tiktok"
                        ]
                      },
                      "accountId": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      "handle": {
                        "type": "string"
                      },
                      "candidates": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "accountId": {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                            },
                            "platform": {
                              "type": "string",
                              "enum": [
                                "instagram",
                                "facebook",
                                "threads",
                                "tiktok"
                              ]
                            },
                            "handle": {
                              "type": "string"
                            },
                            "name": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "status": {
                              "type": "string"
                            }
                          },
                          "required": [
                            "accountId",
                            "platform",
                            "handle",
                            "name",
                            "status"
                          ]
                        }
                      }
                    },
                    "required": [
                      "reason",
                      "path",
                      "message",
                      "fix"
                    ],
                    "additionalProperties": {}
                  }
                }
              },
              "required": [
                "platform",
                "accountId",
                "handle",
                "issues"
              ]
            },
            "description": "Target yang dilewati (`skipInvalid: true`) beserta masalahnya"
          },
          "captionAdjustments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "platform": {
                  "type": "string",
                  "enum": [
                    "instagram",
                    "facebook",
                    "threads",
                    "tiktok"
                  ]
                },
                "accountId": {
                  "type": "string",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                },
                "limit": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "originalLength": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "length": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "hashtagsRemoved": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "sentencesRemoved": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "cutMidSentence": {
                  "type": "boolean"
                },
                "caption": {
                  "type": "string"
                }
              },
              "required": [
                "platform",
                "accountId",
                "limit",
                "originalLength",
                "length",
                "hashtagsRemoved",
                "sentencesRemoved",
                "cutMidSentence",
                "caption"
              ]
            },
            "description": "Caption yang diringkas (`autoFitCaptions: true`)"
          }
        },
        "required": [
          "id",
          "carouselId",
          "carouselTitle",
          "kind",
          "media",
          "thread",
          "status",
          "paused",
          "publishAt",
          "format",
          "video",
          "videoDurationSec",
          "seriesId",
          "seriesSeq",
          "targets",
          "calendarUrl",
          "publishNow",
          "skipped",
          "captionAdjustments"
        ]
      },
      "UploadCreated": {
        "type": "object",
        "properties": {
          "uploadId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "image",
              "video"
            ]
          },
          "uploadUrl": {
            "type": "string",
            "description": "PUT file mentah ke URL ini (berlaku 15 menit) dengan `headers`"
          },
          "headers": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": "string"
            }
          },
          "expiresAt": {
            "type": "string"
          },
          "limits": {
            "type": "object",
            "properties": {
              "videoMaxMb": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "videoMaxSec": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "slideVideoMaxSec": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "imageMaxBytes": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "videoMaxBytes": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "videoMaxLongSide": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "videoMaxFps": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "imageMime": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "videoMime": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": [
              "videoMaxMb",
              "videoMaxSec",
              "slideVideoMaxSec",
              "imageMaxBytes",
              "videoMaxBytes",
              "videoMaxLongSide",
              "videoMaxFps",
              "imageMime",
              "videoMime"
            ]
          },
          "next": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "PUT"
              },
              "url": {
                "type": "string"
              },
              "headers": {
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {
                  "type": "string"
                }
              },
              "thenCall": {
                "type": "string"
              }
            },
            "required": [
              "method",
              "url",
              "headers",
              "thenCall"
            ]
          }
        },
        "required": [
          "uploadId",
          "kind",
          "uploadUrl",
          "headers",
          "expiresAt",
          "limits",
          "next"
        ]
      },
      "UploadStatus": {
        "type": "object",
        "properties": {
          "uploadId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "status": {
            "type": "string",
            "enum": [
              "uploading",
              "processing",
              "ready",
              "rejected"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "image",
              "video"
            ]
          },
          "media": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "image",
                      "video"
                    ]
                  },
                  "mime": {
                    "type": "string"
                  },
                  "bytes": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "width": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "height": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "filename": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "createdAt": {
                    "type": "string"
                  },
                  "fileUrl": {
                    "type": "string"
                  },
                  "thumbUrl": {
                    "type": "string"
                  },
                  "video": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "durationSec": {
                            "type": "number"
                          },
                          "width": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "height": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "fps": {
                            "type": "number"
                          },
                          "codec": {
                            "type": "string"
                          },
                          "audioCodec": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "hdr": {
                            "type": "boolean"
                          },
                          "keyframes": {
                            "type": "array",
                            "items": {
                              "type": "number"
                            }
                          }
                        },
                        "required": [
                          "durationSec",
                          "width",
                          "height",
                          "fps",
                          "codec",
                          "audioCodec",
                          "hdr",
                          "keyframes"
                        ],
                        "additionalProperties": {}
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "id",
                  "kind",
                  "mime",
                  "bytes",
                  "width",
                  "height",
                  "filename",
                  "createdAt",
                  "fileUrl",
                  "thumbUrl",
                  "video"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Ada bila `ready`: `media.id` dipakai di `POST /schedules` `media[].mediaId`"
          },
          "rejection": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "params": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {
                      "type": [
                        "string",
                        "number"
                      ]
                    }
                  },
                  "message": {
                    "type": "string"
                  }
                },
                "required": [
                  "code",
                  "params",
                  "message"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Ada bila `rejected`: pesan berisi cara memperbaiki"
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "`hdr` (diterima apa adanya), `remuxed` (MOV → MP4)"
          }
        },
        "required": [
          "uploadId",
          "status",
          "kind",
          "media",
          "rejection",
          "notes"
        ]
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
            "description": "accountId untuk `accounts.<platform>` di POST /schedules"
          },
          "platform": {
            "type": "string",
            "enum": [
              "instagram",
              "facebook",
              "threads",
              "tiktok"
            ]
          },
          "handle": {
            "type": "string"
          },
          "name": {
            "description": "Nama tampilan; Facebook = nama Page",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "expiring",
              "expired",
              "revoked",
              "error"
            ]
          },
          "connected": {
            "type": "boolean",
            "description": "Token tersambung (`active` / `expiring`)"
          },
          "suspended": {
            "type": "boolean",
            "description": "Ditangguhkan karena paket berakhir / melebihi kuota akun paket (aditif): `status` tetap `revoked`, akun aktif lagi otomatis saat paket dibayar atau di-upgrade (tidak perlu dihubungkan ulang)"
          },
          "canPost": {
            "type": "boolean",
            "description": "Bisa dipakai di jadwal sekarang"
          },
          "blockedReason": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "ACCOUNT_DISCONNECTED",
                  "ACCOUNT_SUSPENDED",
                  "AUTOPOST_OFF",
                  "PLAN_REQUIRED"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Alasan mesin bila `canPost` false"
          },
          "captionLimits": {
            "type": "object",
            "properties": {
              "carousel": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "reels": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "hashtagsMax": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "carousel",
              "reels",
              "hashtagsMax"
            ]
          },
          "profileUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "connectedAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "platform",
          "handle",
          "name",
          "status",
          "connected",
          "suspended",
          "canPost",
          "blockedReason",
          "captionLimits",
          "profileUrl",
          "avatarUrl",
          "expiresAt",
          "connectedAt"
        ]
      },
      "TiktokCreatorInfo": {
        "type": "object",
        "properties": {
          "accountId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "nickname": {
            "type": [
              "string",
              "null"
            ]
          },
          "username": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "privacyLevelOptions": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "PUBLIC_TO_EVERYONE",
                "MUTUAL_FOLLOW_FRIENDS",
                "FOLLOWER_OF_CREATOR",
                "SELF_ONLY"
              ]
            },
            "description": "`privacy_level_options` TikTok apa adanya"
          },
          "selectablePrivacyLevels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "PUBLIC_TO_EVERYONE",
                "MUTUAL_FOLLOW_FRIENDS",
                "FOLLOWER_OF_CREATOR",
                "SELF_ONLY"
              ]
            }
          },
          "allowedPrivacyLevels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "PUBLIC_TO_EVERYONE",
                "MUTUAL_FOLLOW_FRIENDS",
                "FOLLOWER_OF_CREATOR",
                "SELF_ONLY"
              ]
            },
            "description": "Nilai sah `tiktok.privacyLevel` (opsi kreator ∩ kebijakan audit Posto). Tanpa bawaan."
          },
          "audited": {
            "type": "boolean"
          },
          "commentDisabled": {
            "type": "boolean",
            "description": "true → `disableComment` harus true"
          },
          "duetDisabled": {
            "type": "boolean"
          },
          "stitchDisabled": {
            "type": "boolean"
          },
          "maxVideoPostDurationSec": {
            "type": [
              "number",
              "null"
            ]
          },
          "canPost": {
            "type": "boolean"
          },
          "blockedReason": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "posting-limit",
                  "banned"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "fetchedAt": {
            "type": "string"
          },
          "policies": {
            "type": "object",
            "properties": {
              "musicUsageConfirmation": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "url"
                ]
              },
              "brandedContentPolicy": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "url"
                ]
              }
            },
            "required": [
              "musicUsageConfirmation",
              "brandedContentPolicy"
            ]
          }
        },
        "required": [
          "accountId",
          "nickname",
          "username",
          "avatarUrl",
          "privacyLevelOptions",
          "selectablePrivacyLevels",
          "allowedPrivacyLevels",
          "audited",
          "commentDisabled",
          "maxVideoPostDurationSec",
          "canPost",
          "blockedReason",
          "fetchedAt",
          "policies"
        ]
      },
      "ScheduleSeries": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "carouselId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "ended",
              "canceled"
            ]
          },
          "pausedReason": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "account_inactive",
                  "subscription",
                  "approval",
                  "carousel_missing",
                  "platform_gate",
                  "manual"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "`manual` = dijeda user/API; lainnya otomatis (account_inactive, subscription, approval, carousel_missing, platform_gate)"
          },
          "rule": {
            "type": "object",
            "properties": {
              "freq": {
                "type": "string",
                "enum": [
                  "daily",
                  "weekly",
                  "monthly"
                ]
              },
              "interval": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "byWeekday": {
                "type": "array",
                "items": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                }
              },
              "byMonthDay": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "time": {
                "type": "string"
              },
              "until": {
                "type": "string"
              },
              "count": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              }
            },
            "required": [
              "freq",
              "interval",
              "time"
            ]
          },
          "timezone": {
            "type": "string"
          },
          "startsOn": {
            "type": "string"
          },
          "versionMode": {
            "type": "string",
            "enum": [
              "latest",
              "fixed"
            ]
          },
          "captionVariation": {
            "type": "boolean"
          },
          "format": {
            "type": "string",
            "enum": [
              "carousel",
              "reels"
            ]
          },
          "video": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "fit": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "reflow",
                      "frame"
                    ]
                  },
                  "secondsPerSlide": {
                    "type": "number"
                  },
                  "transition": {
                    "type": "string",
                    "enum": [
                      "none",
                      "fade",
                      "slide"
                    ]
                  },
                  "animation": {
                    "description": "Animasi isi slide (M7-04); jadwal lama tanpa kunci ini = `none`",
                    "type": "string",
                    "enum": [
                      "none",
                      "subtle",
                      "dynamic"
                    ]
                  },
                  "musicTrackId": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "musicVolume": {
                    "type": "number"
                  }
                },
                "required": [
                  "fit",
                  "secondsPerSlide",
                  "transition",
                  "musicTrackId",
                  "musicVolume"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "targets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "platform": {
                  "type": "string",
                  "enum": [
                    "instagram",
                    "facebook",
                    "threads",
                    "tiktok"
                  ]
                },
                "accountId": {
                  "type": "string",
                  "format": "uuid",
                  "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                },
                "handle": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "caption": {
                  "type": "string"
                }
              },
              "required": [
                "platform",
                "accountId",
                "handle",
                "caption"
              ]
            }
          },
          "occurrencesCreated": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "nextPublishAt": {
            "description": "Posting berikutnya (ISO UTC); null = tidak ada lagi",
            "type": [
              "string",
              "null"
            ]
          },
          "upcoming": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Jadwal seri mendatang yang masih menunggu"
          },
          "published": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Kejadian yang sudah terbit (minimal satu akun)"
          },
          "lastError": {
            "type": [
              "string",
              "null"
            ]
          },
          "calendarUrl": {
            "type": "string"
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "carouselId",
          "status",
          "pausedReason",
          "rule",
          "timezone",
          "startsOn",
          "versionMode",
          "captionVariation",
          "format",
          "video",
          "targets",
          "occurrencesCreated",
          "nextPublishAt",
          "upcoming",
          "published",
          "lastError",
          "calendarUrl",
          "createdAt",
          "updatedAt"
        ]
      },
      "VideoExport": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
            "description": "Deterministik per (versi, opsi efektif): permintaan sama = ekspor yang sama"
          },
          "carouselId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "versionId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "rendering",
              "encoding",
              "ready",
              "failed"
            ]
          },
          "progress": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ],
            "description": "0–100 kasar"
          },
          "options": {
            "type": "object",
            "properties": {
              "fit": {
                "type": "string",
                "enum": [
                  "reflow",
                  "frame"
                ]
              },
              "secondsPerSlide": {
                "type": "number"
              },
              "transition": {
                "type": "string",
                "enum": [
                  "none",
                  "fade",
                  "slide"
                ]
              },
              "animation": {
                "description": "Animasi isi slide (M7-04); tidak ada pada ekspor lama = `none`",
                "type": "string",
                "enum": [
                  "none",
                  "subtle",
                  "dynamic"
                ]
              },
              "musicTrackId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "musicVolume": {
                "type": "number"
              },
              "durationSec": {
                "type": "number"
              },
              "slideCount": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "sourceRatio": {
                "type": "string",
                "enum": [
                  "4:5",
                  "1:1",
                  "9:16"
                ]
              }
            },
            "required": [
              "fit",
              "secondsPerSlide",
              "transition",
              "musicTrackId",
              "musicVolume",
              "durationSec",
              "slideCount",
              "sourceRatio"
            ]
          },
          "video": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Link unduh MP4, berlaku sampai `expiresAt` (24 jam)"
                  },
                  "posterUrl": {
                    "type": "string"
                  },
                  "filename": {
                    "type": "string"
                  },
                  "durationSec": {
                    "type": "number"
                  },
                  "sizeBytes": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "width": {
                    "type": "number",
                    "const": 1080
                  },
                  "height": {
                    "type": "number",
                    "const": 1920
                  },
                  "expiresAt": {
                    "type": "string"
                  }
                },
                "required": [
                  "url",
                  "posterUrl",
                  "filename",
                  "durationSec",
                  "sizeBytes",
                  "width",
                  "height",
                  "expiresAt"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Hanya saat `ready`"
          },
          "error": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "enum": [
                      "render_failed",
                      "encode_failed",
                      "timeout",
                      "music_unavailable",
                      "unknown"
                    ]
                  },
                  "message": {
                    "type": "string"
                  }
                },
                "required": [
                  "code",
                  "message"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "carouselId",
          "versionId",
          "status",
          "progress",
          "options",
          "video",
          "error",
          "createdAt"
        ]
      },
      "Video": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
            "description": "Id ekspor (sama dengan `id` dari POST /carousels/{id}/video-exports)"
          },
          "carousel": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "title": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "deleted": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "id",
                  "title",
                  "deleted"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Carousel asal; `deleted: true` = sudah di Sampah/terhapus; null = tidak diketahui"
          },
          "versionId": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "rendering",
              "encoding",
              "ready",
              "failed"
            ]
          },
          "progress": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "enum": [
                      "render_failed",
                      "encode_failed",
                      "timeout",
                      "music_unavailable",
                      "unknown"
                    ]
                  },
                  "message": {
                    "type": "string"
                  }
                },
                "required": [
                  "code",
                  "message"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "options": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "fit": {
                    "type": "string",
                    "enum": [
                      "reflow",
                      "frame"
                    ]
                  },
                  "secondsPerSlide": {
                    "type": "number"
                  },
                  "transition": {
                    "type": "string",
                    "enum": [
                      "none",
                      "fade",
                      "slide"
                    ]
                  },
                  "animation": {
                    "description": "Animasi isi slide (M7-04); tidak ada pada ekspor lama = `none`",
                    "type": "string",
                    "enum": [
                      "none",
                      "subtle",
                      "dynamic"
                    ]
                  },
                  "musicTrackId": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "musicVolume": {
                    "type": "number"
                  },
                  "durationSec": {
                    "type": "number"
                  },
                  "slideCount": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "sourceRatio": {
                    "type": "string",
                    "enum": [
                      "4:5",
                      "1:1",
                      "9:16"
                    ]
                  }
                },
                "required": [
                  "fit",
                  "secondsPerSlide",
                  "transition",
                  "musicTrackId",
                  "musicVolume",
                  "durationSec",
                  "slideCount",
                  "sourceRatio"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "storage": {
            "type": "string",
            "enum": [
              "temporary",
              "saved"
            ],
            "description": "`temporary` = salinan 24 jam (tanpa kuota), `saved` = tersimpan permanen (memakai kuota penyimpanan)"
          },
          "expiresAt": {
            "description": "Kedaluwarsa salinan sementara (ISO UTC); null = tersimpan",
            "type": [
              "string",
              "null"
            ]
          },
          "save": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "saving",
                      "saved",
                      "failed"
                    ]
                  },
                  "savedAt": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "error": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "enum": [
                              "storage_quota",
                              "expired",
                              "unknown"
                            ]
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "message"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "status",
                  "savedAt",
                  "error"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Status \"Simpan permanen\"; null = belum pernah diminta"
          },
          "source": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "web",
                  "api",
                  "schedule"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Asal ekspor: studio, API/MCP, jadwal"
          },
          "video": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Putar MP4"
                  },
                  "downloadUrl": {
                    "type": "string",
                    "description": "Unduh MP4 (attachment)"
                  },
                  "posterUrl": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "filename": {
                    "type": "string"
                  },
                  "durationSec": {
                    "type": "number"
                  },
                  "sizeBytes": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "width": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "height": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "linksExpireAt": {
                    "type": "string",
                    "description": "Batas berlaku `url`/`downloadUrl`/`posterUrl`: tersimpan = tautan bertanda tangan 1 jam (ambil ulang daftar), sementara = `expiresAt`"
                  }
                },
                "required": [
                  "url",
                  "downloadUrl",
                  "posterUrl",
                  "filename",
                  "durationSec",
                  "sizeBytes",
                  "width",
                  "height",
                  "linksExpireAt"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Hanya saat `ready`"
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "carousel",
          "versionId",
          "status",
          "progress",
          "error",
          "options",
          "storage",
          "expiresAt",
          "save",
          "source",
          "video",
          "createdAt"
        ]
      },
      "Media": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "origin": {
            "type": "string",
            "enum": [
              "ai",
              "cutout",
              "upload"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "generate",
              "edit",
              "cutout",
              "upload"
            ],
            "description": "`generate` = foto AI baru, `edit` = foto AI dari referensi produk/karakter, `cutout` = latar dihapus"
          },
          "tier": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "standard",
                  "high"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "style": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "key": {
                    "type": "string"
                  },
                  "name": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "en": {
                            "type": "string"
                          },
                          "ms": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "en",
                          "ms"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "key",
                  "name"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Jenis gambar (preset); foto lama tanpa catatan = null"
          },
          "carousel": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "title": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "deleted": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "id",
                  "title",
                  "deleted"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Carousel asal; `deleted: true` = sudah di Sampah/terhapus; null = tidak diketahui"
          },
          "slide": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ],
            "description": "Nomor slide (1-based) di dokumen carousel saat ini"
          },
          "used": {
            "type": "boolean",
            "description": "Dirujuk carousel aktif atau brand kit → tidak bisa dihapus (409)"
          },
          "mime": {
            "type": "string"
          },
          "bytes": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "width": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "height": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "filename": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "description": "Tautan bertanda tangan ke file asli (berlaku sampai `linksExpireAt`)"
          },
          "downloadUrl": {
            "type": "string",
            "description": "Unduh (attachment, nama `filename`)"
          },
          "linksExpireAt": {
            "type": "string"
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "origin",
          "kind",
          "tier",
          "style",
          "carousel",
          "slide",
          "used",
          "mime",
          "bytes",
          "width",
          "height",
          "filename",
          "url",
          "downloadUrl",
          "linksExpireAt",
          "createdAt"
        ]
      },
      "Brand": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "name": {
            "type": "string"
          },
          "handle": {
            "type": [
              "string",
              "null"
            ]
          },
          "niche": {
            "type": [
              "string",
              "null"
            ]
          },
          "lang": {
            "type": "string"
          },
          "tone": {
            "type": [
              "string",
              "null"
            ]
          },
          "colors": {
            "anyOf": [
              {
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {
                  "type": "string"
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "logoUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "personal",
              "agency",
              "client"
            ]
          },
          "credits": {
            "type": "object",
            "properties": {
              "quotaPerMonth": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "usedThisPeriod": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "quotaPerMonth",
              "usedThisPeriod"
            ]
          }
        },
        "required": [
          "id",
          "name",
          "handle",
          "niche",
          "lang",
          "tone",
          "colors",
          "logoUrl",
          "kind",
          "credits"
        ]
      },
      "Template": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "family": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "tier": {
            "type": "string",
            "enum": [
              "free",
              "pro"
            ]
          },
          "version": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "ratios": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "4:5",
                "1:1",
                "9:16"
              ]
            }
          },
          "previewUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "private": {
            "type": "boolean"
          },
          "locked": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "name",
          "family",
          "category",
          "tier",
          "version",
          "ratios",
          "previewUrl",
          "private",
          "locked"
        ]
      },
      "Idea": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          },
          "angle": {
            "type": [
              "string",
              "null"
            ]
          },
          "sourceUrl": {
            "type": "string"
          },
          "score": {
            "type": "number"
          },
          "category": {
            "type": "string"
          },
          "publishedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "moment": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "name"
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "title",
          "summary",
          "angle",
          "sourceUrl",
          "score",
          "category",
          "publishedAt",
          "moment"
        ]
      },
      "Credits": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "wallets": {
            "type": "object",
            "properties": {
              "plan": {
                "type": "object",
                "properties": {
                  "balance": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "expiresAt": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "balance",
                  "expiresAt"
                ]
              },
              "topup": {
                "type": "object",
                "properties": {
                  "balance": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  "expiresAt": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "balance",
                  "expiresAt"
                ]
              }
            },
            "required": [
              "plan",
              "topup"
            ]
          },
          "dailyLimit": {
            "type": "object",
            "properties": {
              "limit": {
                "anyOf": [
                  {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "used": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              }
            },
            "required": [
              "limit",
              "used"
            ]
          },
          "clientQuota": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "quotaPerMonth": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": -9007199254740991,
                        "maximum": 9007199254740991
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "usedThisPeriod": {
                    "type": "integer",
                    "minimum": -9007199254740991,
                    "maximum": 9007199254740991
                  }
                },
                "required": [
                  "quotaPerMonth",
                  "usedThisPeriod"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "ledger": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "at": {
                  "type": "string"
                },
                "delta": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "type": {
                  "type": "string"
                },
                "reason": {
                  "type": "string"
                },
                "ref": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "id": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "type",
                        "id"
                      ]
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "balanceAfter": {
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                }
              },
              "required": [
                "at",
                "delta",
                "type",
                "reason",
                "ref",
                "balanceAfter"
              ]
            }
          },
          "topupUrl": {
            "type": "string"
          }
        },
        "required": [
          "total",
          "wallets",
          "dailyLimit",
          "clientQuota",
          "ledger",
          "topupUrl"
        ]
      },
      "Batch": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "progress": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "done": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              "failed": {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              }
            },
            "required": [
              "total",
              "done",
              "failed"
            ]
          },
          "creditsSpent": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "status": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "carouselId": {
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "key",
                "title",
                "status",
                "carouselId"
              ]
            }
          },
          "batchUrl": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "status",
          "progress",
          "creditsSpent",
          "items",
          "batchUrl"
        ]
      },
      "BatchCreated": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "status": {
            "type": "string"
          },
          "plan": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              },
              "required": [
                "key",
                "title"
              ]
            }
          },
          "creditsTotal": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "available": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "batchUrl": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "status",
          "plan",
          "creditsTotal",
          "available",
          "batchUrl"
        ]
      },
      "ExportJob": {
        "type": "object",
        "properties": {
          "jobId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "done",
              "failed"
            ]
          },
          "url": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string"
          },
          "sizeBytes": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "jobId",
          "status"
        ]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "url": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "carousel.ready",
                "carousel.failed",
                "image.ready",
                "post.published",
                "post.failed",
                "credits.low",
                "approval.decided",
                "series.paused",
                "series.ended"
              ]
            }
          },
          "active": {
            "type": "boolean",
            "description": "false = dimatikan (otomatis setelah gagal 3 hari berturut)"
          },
          "failureCount": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "Kiriman berturut gagal setelah semua retry"
          },
          "disabledAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "previousSecretExpiresAt": {
            "description": "Rahasia lama masih ikut ditandatangani sampai waktu ini (24 jam setelah rotasi)",
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "url",
          "description",
          "events",
          "active",
          "failureCount",
          "disabledAt",
          "previousSecretExpiresAt",
          "createdAt"
        ]
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
            "description": "= header X-Posto-Delivery"
          },
          "eventId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
            "description": "= `id` amplop (abaikan duplikat)"
          },
          "event": {
            "type": "string",
            "enum": [
              "ping",
              "carousel.ready",
              "carousel.failed",
              "image.ready",
              "post.published",
              "post.failed",
              "credits.low",
              "approval.decided",
              "series.paused",
              "series.ended"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "delivered",
              "pending",
              "failed"
            ]
          },
          "attempt": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991,
            "description": "1 = kiriman pertama, maks 7 (6 retry)"
          },
          "responseStatus": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "responseBody": {
            "description": "Potongan balasan endpoint (≤ 500 karakter) atau alasan gagal",
            "type": [
              "string",
              "null"
            ]
          },
          "deliveredAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "nextRetryAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "eventId",
          "event",
          "status",
          "attempt",
          "responseStatus",
          "responseBody",
          "deliveredAt",
          "nextRetryAt",
          "createdAt"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "UNAUTHORIZED",
                  "FORBIDDEN",
                  "EMAIL_NOT_VERIFIED",
                  "NOT_FOUND",
                  "VALIDATION",
                  "NO_CREDITS",
                  "RATE_LIMITED",
                  "PROVIDER_ERROR",
                  "SERVICE_UNAVAILABLE",
                  "CONFLICT",
                  "INTERNAL"
                ]
              },
              "message": {
                "type": "string",
                "description": "Untuk manusia, bahasa `Accept-Language`, menyebut cara memperbaiki"
              },
              "reason": {
                "description": "Kode mesin UPPER_SNAKE yang stabil (ADR 0080/0081), mis. INSUFFICIENT_CREDITS, INVALID_INPUT, NOT_FOUND, SLIDES_REDUCED, SOURCE_TOO_THIN, IDEMPOTENCY_KEY_REUSED, AMBIGUOUS_ACCOUNT, CAPTION_TOO_LONG, MULTIPLE_ISSUES. `code` tetap kode 04 §1.3.",
                "type": "string"
              },
              "fix": {
                "description": "Langkah perbaikan singkat untuk agen/integrasi (bahasa `Accept-Language`); tidak selalu ada",
                "type": "string"
              },
              "details": {
                "description": "`issues[]` (jalur jadwal ADR 0080: semua masalah sekaligus — reason, path, message, fix, platform, accountId, candidates)",
                "type": "object",
                "propertyNames": {
                  "type": "string"
                },
                "additionalProperties": {}
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "ok",
          "error"
        ],
        "example": {
          "ok": false,
          "error": {
            "code": "NO_CREDITS",
            "message": "Credit AI kurang 2. Tambah Credit AI?",
            "reason": "INSUFFICIENT_CREDITS",
            "fix": "Minta user menambah Credit AI (details.topupUrl bila ada) atau kurangi jumlah slide, lalu ulangi.",
            "details": {
              "required": 5,
              "available": 3
            }
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "pk_live_…"
      }
    }
  }
}
