Ringkasan
Ikhtisar API
Setiap endpoint Sofia API v1 dengan parameter, scope, dan contohnya, serta playground untuk mencoba masing-masing dengan kunci API Anda sendiri.
URL dasar https://api.sofia-post.com/api · Dokumen OpenAPI
Sofia API memberi kode Anda akses ke akun Sofia Anda: usaha di Workspace Anda, jaringan terhubungnya, pustaka mediannya, postingannya, dan statistiknya. Ini adalah API REST lewat HTTPS; permintaan dan responsnya berformat JSON. API ini memungkinkan Anda untuk:
- Menerbitkan: sekarang, pada tanggal tertentu, atau sebagai draf, ke satu atau beberapa jaringan sekaligus.
- Memeriksa sebelum menerbitkan: simulasi memberi tahu apakah setiap jaringan akan menerima postingan, tanpa menulis apa pun.
- Mengelola media: unggah file atau impor dari URL ke pustaka media sebuah usaha.
- Memantau postingan: baca status setiap jaringan, tautan permanennya, atau alasan kegagalan. Webhook bertanda tangan juga bisa memberi tahu Anda.
- Membaca statistik: angka terbaru yang dikumpulkan Sofia untuk setiap akun terhubung.
- Menghubungkan jaringan: buat tautan terhosting yang memungkinkan pemilik menghubungkan jaringan yang belum ada.
SDK dan integrasi
- CLI `sofia`: CLI, yang dipublikasikan di npm dengan nama
sofia-post, untuk mengendalikan Sofia dari terminal. - Server MCP: hubungkan Sofia ke agen AI Anda.
- Zapier: integrasi Sofia terhubung dengan kunci pribadi Anda. Integrasi ini menyediakan pemicu “Post Published” dan “Post Failed”, tindakan “Create Post” (menerbitkan, menjadwalkan, atau menyimpan draf), dan pencarian “Find Post”. Belum diajukan ke direktori publik Zapier.
Autentikasi
Setiap panggilan membawa token Bearer di header Authorization. Sofia membaca ulang hak yang melekat padanya pada setiap panggilan: orang yang dikeluarkan dari sebuah Workspace, atau otorisasi yang dicabut, menghentikan token sejak permintaan berikutnya.
Ada dua cara untuk mengautentikasi:
| Metode | Untuk | Token |
|---|---|---|
| Kunci pribadi | Mengotomatiskan akun Anda sendiri, skrip, agen | sofia_pk_live_…, berlaku hingga kedaluwarsa |
| OAuth, kode otorisasi + PKCE | Produk yang bertindak untuk penggunanya, di Workspace pilihan mereka | sofia_live_at_…, satu jam, dapat diperbarui |
| OAuth, client credentials | Salah satu server Anda yang mengotomatiskan Workspace milik Anda | sofia_live_at_…, satu jam |
Kunci API
Jika Anda mengotomatiskan Workspace Anda sendiri, kunci pribadi sudah cukup. Di aplikasi Sofia, buka Pengaturan › API, tab Akses pribadi, dan buat kunci. Pilih nama, masa berlaku, dan izinnya. Kunci hanya ditampilkan sekali: salin dan simpan di brankas rahasia, jangan pernah di kode Anda.
Buat kunci di Pengaturan › API › Akses pribadi. Kunci bertindak untuk Anda di semua Workspace Anda: usaha yang Anda sebut menentukan Workspace-nya, dan peran Anda di sana menentukan apa yang bisa dilakukan kunci.
Kirim kunci di header Authorization, sebagai token Bearer:
curl https://api.sofia-post.com/api/v1/establishments \
-H "Authorization: Bearer sofia_pk_live_…"`GET /v1/me` memberi tahu untuk siapa kunci bertindak, Workspace-nya, dan izinnya.
Panggilan tanpa izin (scope) yang diperlukan menjawab 403 insufficient_scope.
Token OAuth2
Untuk produk SaaS yang bertindak untuk penggunanya di Workspace mereka sendiri, daftarkan klien OAuth: setiap orang mengizinkan aplikasi Anda di Workspace pilihannya. Token akses OAuth diawali sofia_live_at_…, berlaku satu jam, dan dipakai dengan cara yang sama:
curl https://api.sofia-post.com/api/v1/establishments \
-H "Authorization: Bearer sofia_live_at_…"Anda membuat aplikasi yang akan dihubungkan akun Sofia lain? Alur authorization code dengan PKCE, client credentials, dan scope-nya dijelaskan di OAuth2.
URL dasar
Setiap endpoint berada di bawah satu URL dasar:
https://api.sofia-post.com/api/v1Batas laju
Sofia API menghitung permintaan pada tiga jendela: 15 menit, 24 jam, dan 30 hari.
| Token | 15 menit | 24 jam | 30 hari |
|---|---|---|---|
| Kunci pribadi (per akun) | 150 | 1.000 | 10.000 |
| Klien OAuth | 100 | 500 | 15.000 |
| Klien OAuth, per orang yang mengizinkan (hingga 1.000) | +10 | +25 | +100 |
Header
Setiap respons memberi tahu sisanya, dalam format IETF:
RateLimit: "15m";r=144;t=43, "24h";r=994;t=13543, "30d";r=9994;t=13543
RateLimit-Policy: "15m";q=150;w=900, "24h";q=1000;w=86400, "30d";q=10000;w=2592000r adalah jumlah permintaan yang tersisa, t detik sebelum jendela diatur ulang, q kuota, dan w jendela dalam detik.
Saat sebuah jendela penuh
Responsnya 429 rate_limit_exceeded, dengan header Retry-After dan jendela yang habis di details. Tunggu selama jeda itu sebelum mencoba lagi.
Menggunakan API secara efisien
- Daftarkan webhook daripada memeriksa postingan berulang-ulang.
- Gunakan
limithingga 100 untuk membaca daftar dengan lebih sedikit halaman. - Simpan di cache apa yang jarang berubah: platform, usaha, akun terhubung.
Kesalahan
Setiap kesalahan dijawab dengan status HTTP dan amplop JSON yang sama. code adalah kontrak yang dibaca kode Anda; message ditulis untuk manusia dan bisa berubah.
{
"error": {
"code": "invalid_request",
"message": "The request is invalid",
"details": [
{ "field": "targets[0].text", "code": "required", "message": "targets[0].text is required" }
],
"docUrl": "https://www.sofia-post.com/developers/errors#invalid_request",
"requestId": "2aab5943-6333-4caf-8478-25a85ebd4abf"
}
}detailsmenjelaskan lebih banyak: kolom yang ditolak, alasan sebuah jaringan, jendela batas yang habis.docUrlmengarah ke penjelasan kode itu di halaman ini.requestIdmengidentifikasi permintaan: sampaikan ke dukungan.
Kode kesalahan
| Status | Kode | Arti |
|---|---|---|
| 400 | invalid_request | Body, query, atau parameter tidak valid. Satu rincian per field yang ditolak: field, code (required, is_string, max…), dan message. |
| 400 | invalid_json | Body bukan JSON yang valid. |
| 400 | invalid_cursor | Kursor tidak dikembalikan oleh Sofia API. |
| 400 | webhook_url_invalid | Alamat webhook bukan https, atau mengarah ke alamat privat. |
| 400 | webhook_event_invalid | Event webhook tidak dikenal. |
| 400 | application_name_invalid | Pengaturan › API: nama klien tidak ada atau terlalu panjang. |
| 400 | application_profile_invalid | Pengaturan › API: ada kolom profil klien yang tidak valid; rinciannya menyebutkannya. |
| 400 | logo_invalid | Pengaturan › API: logo ditolak (minimal 180×180 px, PNG, JPEG, atau WebP, maksimal 2 MB). |
| 401 | invalid_token | Token tidak ada, tidak dikenal, kedaluwarsa, atau dicabut, atau orang di baliknya kehilangan hak yang dibawanya. Lihat header WWW-Authenticate. |
| 401 | unauthorized | Autentikasi diperlukan. |
| 402 | subscription_required | Penulisan live (termasuk dry run) memerlukan langganan aktif atau masa percobaan. |
| 403 | insufficient_scope | Token tidak memiliki scope endpoint; rinciannya menyebutkannya. |
| 403 | insufficient_role | Peran Anda di Workspace ini tidak mengizinkan tindakan ini. |
| 403 | live_mode_required | Penulisan nyata dengan token uji. |
| 403 | route_closed_to_applications | Endpoint ini tidak terbuka untuk aplikasi. |
| 403 | forbidden | Akses ditolak. |
| 403 | session_required | Pengaturan › API: tindakan ini memerlukan sesi Sofia, bukan token. |
| 403 | impersonation_forbidden | Pengaturan › API: tindakan ini ditolak dalam sesi pinjaman. |
| 403 | workspace_owner_required | Hanya pemilik Workspace yang dapat melakukannya. |
| 403 | workspace_member_required | Anda bukan anggota Workspace ini. |
| 404 | route_not_found | Tidak ada endpoint yang menjawab metode dan path ini. |
| 404 | establishment_not_found | Usaha tidak dikenal, atau di luar jangkauan token. |
| 404 | media_not_found | Media tidak dikenal, atau di luar jangkauan token. |
| 404 | post_not_found | Postingan tidak dikenal, atau di luar jangkauan token. |
| 404 | webhook_not_found | Webhook tidak dikenal, atau milik aplikasi lain. |
| 404 | not_found | Sumber daya tidak ada. |
| 404 | application_not_found | Pengaturan › API: klien tidak dikenal. |
| 404 | grant_not_found | Otorisasi tidak dikenal, atau sudah dicabut. |
| 404 | personal_key_not_found | Pengaturan › API: kunci pribadi tidak dikenal. |
| 404 | consent_not_found | Permintaan otorisasi sudah kedaluwarsa atau tidak ada: mulai lagi dari endpoint otorisasi. |
| 405 | method_not_allowed | Metode ini tidak diizinkan pada endpoint ini. |
| 409 | post_in_flight | Sebuah jaringan sedang mengirim postingan: coba hapus lagi sebentar lagi. |
| 409 | post_not_editable | Sebuah jaringan sudah mengirim postingan: tidak dapat diedit lagi. |
| 409 | account_already_connected | Jaringan ini sudah terhubung ke usaha. |
| 409 | webhook_limit_reached | Aplikasi sudah memiliki 10 webhook. |
| 409 | idempotency_in_progress | Permintaan pertama dengan Idempotency-Key ini masih berjalan. |
| 409 | conflict | Permintaan bertentangan dengan keadaan sumber daya saat ini. |
| 409 | scope_removal_forbidden | Pengaturan › API: izin klien dapat ditambahkan tetapi tidak dapat dihapus. |
| 409 | public_client_has_no_secret | Pengaturan › API: klien publik tidak memiliki secret. |
| 413 | payload_too_large | File melebihi batas unggah. |
| 415 | unsupported_media_type | Tipe konten tidak didukung. |
| 422 | post_refused | Sebuah jaringan, usaha, atau paket Anda akan menolak postingan. Satu rincian per alasan, masing-masing dengan message-nya. |
| 422 | media_import_refused | Media tidak dapat diimpor dari URL ini; rinciannya menyebut alasannya. |
| 422 | media_upload_refused | File yang diunggah bukan gambar atau video yang didukung. |
| 422 | platform_not_offered | Jaringan ini tidak ditawarkan untuk dihubungkan. |
| 422 | idempotency_key_reused | Idempotency-Key ini dipakai dengan body yang berbeda. |
| 422 | unprocessable_entity | Permintaan dipahami tetapi tidak dapat diproses. |
| 429 | rate_limit_exceeded | Jendela batas laju penuh: tunggu sesuai Retry-After. |
Alasan sebuah postingan ditolak
post_refused mendaftar setiap alasan di details[].code:
| Kode | Arti |
|---|---|
unsupported_platform | Jaringan ini tidak didukung. |
duplicate_platform | Jaringan yang sama disebut dua kali. |
unsupported_format | Jaringan ini tidak menawarkan format ini. |
caption_too_long | Teks terlalu panjang (max, actual). |
too_many_hashtags | Terlalu banyak hashtag (max, actual). |
too_many_mentions | Terlalu banyak mention (max, actual). |
too_many_thread_posts | Thread terlalu panjang (max, actual). |
too_many_media | Terlalu banyak media (max, actual). |
media_mix_refused | Foto dan video tidak dapat dicampur di jaringan ini. |
media_required | Jaringan ini memerlukan foto atau video. |
media_type_refused | Jaringan ini tidak menerima jenis media ini. |
scheduled_in_past | scheduledAt sudah lewat. |
scheduled_at_invalid | Postingan terjadwal memerlukan scheduledAt di masa depan. |
account_not_connected | Tidak ada akun yang terhubung di jaringan ini untuk usaha ini. |
account_ambiguous | Beberapa akun terhubung di jaringan ini: sebutkan satu dengan accountId. |
media_not_found | Media tidak ada di pustaka usaha ini. |
media_url_invalid | URL media harus berupa alamat https publik. |
platform_unavailable | Jaringan ini belum dibuka di Sofia. |
publication_quota_exceeded | Kuota publikasi paket Anda telah tercapai. |
Menangani kesalahan
- Dasarkan logika Anda pada
code, jangan pernah padamessage. - Coba lagi
429setelahRetry-After, dan5xxdengan backoff eksponensial. - Jangan pernah mengulang
4xxyang sama persis: perbaiki dulu permintaannya. - Catat
requestIdpada setiap kegagalan.
Paginasi
Daftar (GET /v1/posts, GET /v1/media) dikembalikan dengan yang terbaru lebih dulu, satu halaman sekali. limit menentukan ukuran halaman, dari 1 sampai 100 (bawaan 20).
{
"data": [ … ],
"nextCursor": "WyIyMDI2LTEwLTI3VDE1OjExOjU5LjAxN1oiLCIx…"
}Teruskan nextCursor sebagai cursor untuk membaca halaman berikutnya. Jika nextCursor tidak ada, Anda sudah sampai di akhir.
let cursor;
do {
const url = new URL('https://api.sofia-post.com/api/v1/posts');
url.searchParams.set('limit', '100');
if (cursor) url.searchParams.set('cursor', cursor);
const page = await globalThis.fetch(url, { headers: { Authorization: `Bearer ${key}` } }).then((r) => r.json());
handle(page.data);
cursor = page.nextCursor;
} while (cursor);Kursor bersifat buram: jangan pernah membuat atau mengubahnya. Kursor yang tidak dikembalikan Sofia menjawab 400 invalid_cursor.
Idempotensi
Kesalahan jaringan bisa membuat Anda ragu apakah sebuah postingan sudah dibuat. Kirim header Idempotency-Key dengan POST /v1/posts dan POST /v1/media, lalu coba lagi dengan kunci yang sama: Sofia menjawab apa yang dijawabnya pertama kali, dan tidak membuat apa pun secara ganda.
curl -X POST https://api.sofia-post.com/api/v1/posts \
-H "Authorization: Bearer $SOFIA_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-d @post.json- Gunakan kunci acak baru (UUID) untuk setiap postingan baru, dan kunci yang sama untuk setiap percobaan ulang postingan itu.
- Kunci yang sama dengan isi berbeda menjawab
422 idempotency_key_reused. - Selama permintaan pertama masih berjalan, kunci yang sama menjawab
409 idempotency_in_progress: coba lagi sebentar lagi.
Mode uji dan simulasi
Simulasi. Tambahkan ?dry_run=true ke POST /v1/posts: Sofia menjalankan pemeriksaan postingan sungguhan (aturan setiap jaringan, akun terhubung, media, tanggal, dan paket Anda) tanpa menyimpan atau mengirim apa pun. Rincian respons ada di halaman Menerbitkan.
Mode uji. Aplikasi yang dibuat dalam mode test (token sofia_test_at_…) membaca Workspace asli Anda tetapi tidak pernah menulis di sana: postingannya disimulasikan dan dinilai dengan aturan yang sama, dan setiap penulisan sungguhan menjawab 403 live_mode_required. Kunci dan klien yang dibuat di Pengaturan › API berada dalam mode live; gunakan simulasi untuk memeriksa tanpa menerbitkan.
OAuth
/v1/oauth/authorizeMulai otorisasiBuka di browser pengguna. Klien tidak dikenal atau redirect_uri belum terdaftar menghasilkan 400; selain itu diarahkan ke layar persetujuan Sofia.GET/.well-known/oauth-authorization-server/api/v1/oauthAmbil metadata serverMengembalikan metadata server otorisasi OAuth 2.0 dari Sofia API (RFC 8414), agar klien dapat menemukan endpoint dan opsi yang didukung.POST/v1/oauth/tokenTerbitkan access tokenMenukar client_credentials, authorization_code dengan PKCE, atau refresh_token sekali pakai dengan token buram berlaku 3600 detik untuk satu Workspace.Akun
Platform
Usaha
/v1/establishmentsDaftar usahaMendaftar usaha di Workspace tempat token bertindak. Pakai pengenalnya sebagai establishmentId saat memublikasikan, mendaftar media, atau membaca insight.GET/v1/establishments/{id}/accountsDaftar akun yang terhubungMendaftar jaringan yang terhubung ke sebuah usaha, tanpa token atau secret jaringan, hanya yang perlu untuk menamai akun dan memilihnya sebagai accountId.POST/v1/establishments/{id}/connection-linksBuat tautan koneksiMengembalikan tautan terhosting tempat orang mengotorisasi jaringan di Sofia, sehingga token jaringan tak sampai ke aplikasi Anda. Berlaku 30 menit.GET/v1/establishments/{id}/insightsAmbil insight usahaMengembalikan angka valid terbaru yang dikumpulkan Sofia untuk setiap akun yang terhubung. Akun yang belum dikumpulkan terbaca awaiting, tidak pernah nol.Media
/v1/mediaDaftar mediaMendaftar pustaka media sebuah usaha, terbaru lebih dulu, per halaman, dengan URL bertanda tangan untuk jendela saat ini. Berfungsi di mode uji dan live.POST/v1/mediaImpor atau unggah mediaMenambahkan file (multipart) atau URL https yang diambil Sofia ke pustaka media sebuah usaha. Perlu aplikasi live dan langganan aktif.GET/v1/media/{id}Ambil mediaMengembalikan satu media dari pustaka dengan URL bertanda tangan yang berlaku untuk jendela saat ini, agar pengenalnya bisa dipakai ulang di postingan.DELETE/v1/media/{id}Hapus mediaMenghapus media dari pustaka usahanya, seperti yang dilakukan aplikasi. File tidak dimusnahkan dan postingan terjadwal tetap memakai visualnya.Postingan
/v1/postsDaftar postinganMendaftar postingan usaha yang dijangkau token, terbaru lebih dulu, dapat difilter menurut usaha, status, rentang tanggal, dan penulis, per halaman.POST/v1/postsPublikasikan postinganAplikasi live memublikasikan langsung, menjadwalkan, atau menyimpan draf; aplikasi uji hanya mensimulasikan. Dengan ?dry_run=true semua dicek tanpa menulis.GET/v1/posts/{id}Ambil postinganMengembalikan postingan dengan status tiap jaringan, tautan, dan kesalahan bila gagal. Live membaca postingan apa pun di Workspace, uji yang disimulasikan.PATCH/v1/posts/{id}Ubah postinganSebelum jaringan mengirim, mengganti targets, mengatur scheduledAt, atau memindahkan postingan antara draft dan scheduled. Kolom yang dihilangkan tetap.DELETE/v1/posts/{id}Hapus postinganMenghapus postingan seperti di aplikasi: yang terjadwal tidak dikirim, yang terbit dihapus dari jaringannya. Aplikasi uji tak punya yang nyata untuk dihapus.Webhook
/v1/webhooksDaftar webhookMendaftar webhook aplikasi tanpa signing secret-nya, yang hanya dikembalikan satu kali saat webhook didaftarkan, sehingga tidak bisa diambil lagi.POST/v1/webhooksDaftarkan webhookMendaftarkan URL https yang dipanggil Sofia dengan event JSON bertanda tangan, diulang hingga lima kali bila gagal. Secret tampil sekali; maksimal 10 webhook.DELETE/v1/webhooks/{id}Hapus webhookMenghapus webhook. Webhook itu tidak menerima apa pun lagi, termasuk pengiriman yang masih menunggu percobaan ulang, dan panggilan ini tidak mengembalikan body.POST/v1/webhooks/{id}/testKirim event ujiMengirim event webhook.test bertanda tangan seperti event lain, tanpa menunggu penerima, agar Anda bisa memeriksa tanda tangan. Maksimal lima per menit.