# API publikasi SosoAPI: autentikasi, permintaan, dan hasil

URL kanonis: https://sosoapi.ai/id/docs/publishing-api-reference

Bangun integrasi publikasi sisi server dengan satu Scheduled Post per tujuan. Referensi ini mencakup kontrak API publikasi yang ditinjau pada 20 Oktober 2026. Contoh berisi placeholder dan tidak dijalankan pada halaman ini.

## 1. Autentikasi dari server Anda

Buat kunci API di Aplikasi SosoAPI → Pengaturan → Agents & API Access. Simpan sebagai SOSOAPI_API_KEY di lingkungan server. Permintaan menggunakan Authorization: Bearer <your-key> dan Content-Type: application/json. Jangan pernah menanamkan kunci dalam situs web, bundle aplikasi seluler, URL, atau repositori publik.

Semua endpoint di bawah menggunakan POST dengan body JSON. Kunci dan izin agen terdelegasi dibatasi kemampuan, ruang kerja yang diizinkan, serta keanggotaan terkini pemilik. Pembacaan memerlukan agent:operate dan minimal akses viewer; mutasi publikasi memerlukan agent:publish dan minimal akses editor. Izin tidak dapat memperluas hak pemilik.

Gunakan ruang kerja dan akun terhubung aplikasi saat ini, atau panggil /identity-api/workspace/list dan /identity-api/user/social-accounts/list untuk menemukan ID yang diizinkan bagi Anda. Jangan menebak ID ruang kerja atau akun pelanggan.

```
// Node.js 20+; run only on your server.
const apiKey = process.env.SOSOAPI_API_KEY;
if (!apiKey) throw new Error("Set SOSOAPI_API_KEY on your server");
const apiBase = "https://gqeshlawtcexsapabaui.supabase.co/functions/v1";

async function sosoPost(path, body) {
  const response = await fetch(apiBase + path, {
    method: "POST",
    headers: {
      Authorization: "Bearer " + apiKey,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(body)
  });
  const result = await response.json();
  if (!response.ok) {
    const requestId = result.request_id ?? response.headers.get("x-request-id");
    // Handler errors use code/message; schema-validation 400s instead use
    // success:false and error:{name:"ZodError",message:...}.
    // Preserve status, available code and requestId in server diagnostics.
    // Never log the key or an Authorization header.
    throw new Error("SosoAPI " + response.status + " (" +
      (requestId ?? "no request id") + ")");
  }
  return result;
}
```

## 2. Peta endpoint publikasi

Path ini relatif terhadap base API dalam helper server. Ambil detail Scheduled Post untuk versi terkini, tindakan tersedia, dan hasil publikasinya.

Endpoint Scheduled Posts; setiap permintaan menggunakan POST

| Path | Permintaan | Respons dan batas |

| --- | --- | --- |

| /studio-api/scheduled-posts/list | workspace_id; project_id, status, pasangan waktu, limit, cursor opsional. | posts, next_cursor, returned_count. Pembacaan bercakupan ruang kerja. |

| /studio-api/scheduled-posts/get | id. | post, delivery, actions, attempts, outcomes. Baca versi terkini di sini. |

| /studio-api/scheduled-posts/eligibility | workspace_id, targets; include_quota opsional. | tujuan dan kuota opsional. Pemeriksaan awal hanya baca, bukan pencadangan. |

| /studio-api/scheduled-posts/create | workspace_id, akun persis, provider_payload, konten, scheduled_at, idempotency_key. | post dan deduped. 201 untuk jadwal baru; 200 untuk pengulangan yang cocok. |

| /studio-api/scheduled-posts/bulk-create | workspace_id dan 1–50 targets, masing-masing dengan idempotency_key sendiri. | batch_id, successes, failures. 201 jika setidaknya satu berhasil; 422 jika tidak ada yang berhasil. Periksa kedua array. |

| /studio-api/scheduled-posts/update | id, expected_version, patch; provider_payload yang cocok opsional. | post. Versi kedaluwarsa ditolak; tujuan tidak dapat diubah. |

| /studio-api/scheduled-posts/publish-now | id dan expected_version. | post. Meminta eksekusi segera; tidak membuktikan publikasi. |

| /studio-api/scheduled-posts/retry | id, expected_version; scheduled_at mendatang opsional. | post. Pemulihan khusus status gagal dengan persyaratan bukti; tidak pernah mengirim ulang sembarangan. |

| /studio-api/scheduled-posts/cancel | id dan expected_version. | post. Membatalkan pekerjaan yang belum dipublikasikan; pembatalan jarak jauh mungkin tetap tertunda. |

| /studio-api/scheduled-posts/delete | id dan expected_version. | post. Pemanggil mesin tidak dapat menghapus konten penyedia yang sudah dipublikasikan. |

| /studio-api/scheduled-posts/withdraw-delete | id dan expected_version. | post. Menarik permintaan penghapusan Instagram Login yang terhenti dan hanya untuk verifikasi; mempertahankan konten penyedia. |

## 3. Tampilkan daftar dan halaman tanpa kehilangan cakupan

limit memiliki default 50 dan menerima 1–200. status opsional adalah salah satu dari scheduled, publishing, published, failed, expired, needs_reschedule, cancelled, atau deleted. scheduled_from dan scheduled_to harus disertakan bersama sebagai waktu ISO-8601 dengan offset; akhir harus setelah awal.

next_cursor bernilai null atau objek dengan scheduled_at dan id. Kirim kembali objek lengkap sebagai cursor bersama ruang kerja dan filter yang sama. Endpoint ini tidak menerima filter page, offset, platform, atau social_account_id.

```
await sosoPost("/studio-api/scheduled-posts/list", {
  "workspace_id": "<workspace-uuid>",
  "limit": 50
});
```

```
const first = await sosoPost("/studio-api/scheduled-posts/list", {
  workspace_id: "<workspace-uuid>", limit: 50
});
if (first.next_cursor) {
  const next = await sosoPost("/studio-api/scheduled-posts/list", {
    workspace_id: "<workspace-uuid>", limit: 50, cursor: first.next_cursor
  });
  // Consume next.posts; continue only while next_cursor is not null.
}
```

## 4. Validasi dan buat satu postingan yang ditinjau

Ganti setiap placeholder dengan nilai dari cakupan yang diizinkan dan waktu mendatang. Contoh ini menjadwalkan postingan teks Threads nyata saat dijalankan. Dapatkan konfirmasi orang tersebut mengenai akun, konten, dan waktu sebelum panggilan create.

Atur provider_payload.platform dan publish_options platform tersebut. Server memeriksa kecocokannya dengan akun terpilih. Anda dapat menyertakan project_id untuk mencatat asal postingan; proyek tidak memberi akses publikasi atau mengendalikan jadwal.

Kolom permintaan create dan nilai default

| Kolom | Kontrak |

| --- | --- |

| workspace_id / social_account_id | UUID wajib untuk ruang kerja berizin dan tujuan persis. |

| provider_payload | Diskriminator platform wajib dan publish_options khusus platform. |

| scheduled_at / display_timezone | Waktu ISO-8601 dengan offset wajib; zona waktu tampilan IANA valid, default UTC. |

| idempotency_key | String wajib tanpa spasi awal/akhir, 8–160 karakter, tetap untuk satu maksud ini. |

| caption / hashtags | Caption dapat bernilai null, maksimal 5,000 karakter; default null. Hashtags memiliki default []; maksimal 100 string sepanjang 100 karakter. Batas penyedia dapat lebih ketat. |

| media | Default []; maksimal 20 referensi media terdaftar. Masing-masing memiliki kind image/video dan url kanonis; sertakan asset_id yang siap. Aturan platform dapat lebih ketat. |

| link_url | URL opsional atau null. Tujuan dan jenis postingan harus mendukungnya. |

| local_scheduled_at / schedule_dst_disambiguation | Pasangan opsional: waktu lokal tanpa offset dan exact/earlier/later. Sertakan keduanya atau tidak sama sekali; keduanya harus cocok dengan waktu dan zona waktu yang dimaksud. |

| expires_at / automatic_retry_enabled | Masa kedaluwarsa opsional setelah scheduled_at; null berarti tanpa kedaluwarsa. Percobaan ulang otomatis memiliki default true dan tetap tunduk pada keamanan penyedia. |

| project_id / source_ref | UUID Project opsional yang dapat bernilai null dan objek asal-usul pemanggil. Keduanya tidak mengubah kewenangan. |

```
await sosoPost("/studio-api/scheduled-posts/eligibility", {
  "workspace_id": "<workspace-uuid>",
  "include_quota": true,
  "targets": [
    {
      "social_account_id": "<threads-account-uuid>",
      "media": [],
      "provider_payload": {
        "platform": "threads",
        "publish_options": {
          "post_type": "TEXT"
        }
      },
      "draft": {
        "caption": "A reviewed update from our team.",
        "hashtags": [],
        "scheduled_at": "<future-ISO-8601-instant-with-offset>",
        "display_timezone": "Asia/Hong_Kong"
      }
    }
  ]
});
```

```
await sosoPost("/studio-api/scheduled-posts/create", {
  "workspace_id": "<workspace-uuid>",
  "social_account_id": "<threads-account-uuid>",
  "caption": "A reviewed update from our team.",
  "hashtags": [],
  "media": [],
  "provider_payload": {
    "platform": "threads",
    "publish_options": {
      "post_type": "TEXT"
    }
  },
  "scheduled_at": "<future-ISO-8601-instant-with-offset>",
  "display_timezone": "Asia/Hong_Kong",
  "idempotency_key": "<stable-key-for-this-one-intent>"
});
```

## 5. Baca hasil dan batalkan dengan aman

Create mengembalikan { post, deduped }. List mengembalikan { posts, next_cursor, returned_count }. Get mengembalikan { post, delivery, actions, attempts, outcomes }. Postingan mencakup id, status, version, destination, schedule, serta identitas/permalink penyedia yang tersedia; delivery dan actions menjelaskan progres terkini dan langkah berikutnya yang diizinkan.

Postingan berstatus scheduled atau publishing masih tertunda. Hasil akhir publikasi berstatus published mengonfirmasi publikasi dan menyertakan bukti penyedia yang tersedia untuk postingan; permalink mungkin tidak ada. Jika klien terputus atau respons tertunda, baca postingan yang ada sebelum melaporkan hasil.

Sebelum membatalkan, ambil detail postingan dan sertakan versi numerik terkininya. Hasil dapat berupa cancellation_pending saat SosoAPI membatalkan jadwal yang dipegang penyedia. Membatalkan jadwal tidak menghapus postingan yang sudah dipublikasikan.

```
await sosoPost("/studio-api/scheduled-posts/get", {
  "id": "<scheduled-post-uuid>"
});
```

```
const detail = await sosoPost("/studio-api/scheduled-posts/get", {
  id: "<scheduled-post-uuid>"
});
// Run only after the person confirms cancelling this unpublished post.
await sosoPost("/studio-api/scheduled-posts/cancel", {
  id: detail.post.id, expected_version: detail.post.version
});
```

## 6. Idempotensi, konflik, dan penulisan yang belum pasti

Gunakan idempotency_key yang sama saat mengulangi permintaan create yang sama. Pengulangan yang cocok mengembalikan postingan yang ada dengan deduped=true. Mengubah konten sambil menggunakan kembali kunci menyebabkan konflik. Ini mencegah pembuatan duplikat di SosoAPI; tidak menjamin pengiriman tepat satu kali oleh penyedia.

Untuk pembaruan dan tindakan, sertakan expected_version dari respons detail terbaru. Jika konflik, ambil postingan lagi dan tinjau perubahan terhadap versi baru. Respons hilang adalah alasan memeriksa status yang ada, bukan membuat postingan lain dengan kunci baru.

Pengaman konten duplikat dapat menolak permintaan terpisah dengan konten publik ternormalisasi, akun, dan waktu publikasi berdekatan yang sama. Periksa referensi postingan yang ada jika Anda diizinkan membacanya, dan tanyakan kepada pengguna sebelum mengubah permintaan. Permintaan massal mengembalikan hasil untuk setiap tujuan; sebagian dapat berhasil sementara yang lain gagal.

## 7. Kesalahan, batas laju, dan batas integrasi

Kesalahan handler menggunakan envelope dengan error, message, code opsional, retryable, request_id, details opsional, dan retry_after_seconds. Kesalahan validasi skema 400 mengembalikan struktur berbeda: { success: false, error: { name: "ZodError", message: "…" } }. Pesan validasi saat ini berisi masalah kolom yang diserialisasi, termasuk path-nya; jangan menganggap kolom envelope handler tersedia.

Saat mendiagnosis kegagalan, simpan status HTTP, kode kesalahan, dan ID korelasi dari result.request_id ?? response.headers.get("x-request-id"). Gunakan path kolom validasi untuk memperbaiki permintaan. Untuk kesalahan autentikasi atau izin, perbaiki kredensial atau izin sebelum mencoba lagi.

Batas studio-api saat ini adalah 240 permintaan per menit per pengguna manusia dan 480 per menit dalam alokasi kredensial mesin terpisah pengguna tersebut. Ini batas permintaan, bukan throughput publikasi atau kuota paket. Endpoint lain dan penyedia sosial memiliki batas terpisah. Ikuti header Retry-After terkini pada 429 atau 503 yang dapat dicoba lagi; jangan melakukan loop tanpa jeda.

Baca status dengan interval terbatas saat pengguna mengikuti postingan, atau gunakan tampilan status langsung aplikasi. API ini tidak menjanjikan webhook keluar, SLA pelanggan, fitur identik di semua platform, atau waktu publikasi tetap.

Respons HTTP dan tindakan berikutnya yang bermanfaat

| Status | Makna dan respons |

| --- | --- |

| 400 | Validasi skema dapat mengembalikan success:false dengan ZodError dalam error, bukan envelope handler. Perbaiki masalah kolomnya; gunakan x-request-id jika body tidak memiliki request_id. Permintaan tidak valid atau tidak didukung pada tingkat handler juga dapat menggunakan 400. |

| 401 / 403 | Kredensial hilang/kedaluwarsa atau kemampuan, peran, akses ruang kerja atau akun ditolak. Perbaiki izin atau keanggotaan yang bersangkutan. |

| 404 | Sumber daya tidak tersedia dalam cakupan berizin. Verifikasi identitasnya. |

| 409 | Konflik status/versi, idempotensi, konten duplikat, atau kelayakan. Baca ulang; jangan sembarang mengirim ulang. |

| 422 untuk bulk-create | Tidak ada tujuan yang berhasil. Periksa failures; keberhasilan sebagian menggunakan 201. |

| 429 | Pembatasan laju permintaan. Patuhi Retry-After dan pertahankan identitas maksud yang sama. |

| 503 / 5xx lainnya | Kegagalan layanan sementara atau kesalahan internal. Simpan request_id; periksa status yang ada sebelum mencoba ulang mutasi yang belum pasti. |

- [Matriks kemampuan platform](https://sosoapi.ai/id/docs/publishing-capabilities)

- [Siapkan agen AI Anda sendiri](https://sosoapi.ai/id/docs/quickstart)
