# Panduan Cepat REST API Shager: Dari Kunci Baru Hingga Postingan Terlacak di 40 Akun dalam Tujuh Panggilan

_2026-09-19 · Tur praktis REST API Shager dengan curl dan TypeScript: autentikasi, workspace, channel, media, draf per akun, penjadwalan, cek status, dan klik._

REST API Shager berada di `https://app.shager.ai/api/v1`, melakukan autentikasi dengan `Authorization: Bearer shgr_live_...`, mengembalikan setiap hasil sebagai `{ "data": ... }` dan setiap error sebagai `{ "error": { "code", "message" } }`. Satu siklus distribusi lengkap hanya butuh tujuh panggilan: cek kunci, pilih workspace, daftar channel-nya, unggah media, buat draf dengan caption per akun, jadwalkan, lalu baca status dan klik. Spesifikasi yang bisa dibaca mesin tersedia di [dokumen OpenAPI 3.1](https://app.shager.ai/api/v1/openapi.json).

Semua contoh di bawah langsung jalan begitu Anda mengatur dua variabel lingkungan. Operasi yang sama juga tersedia sebagai tool MCP dengan nama yang sama, jadi apa yang Anda pelajari di sini juga berlaku di Claude Code, Codex, atau Cursor.

## Apa yang Anda perlukan sebelum panggilan pertama?

Sebuah kunci. Bisa dibuat oleh manusia di https://app.shager.ai/dashboard/agents dengan cakupan yang Anda perlukan, atau agen Anda membuat sandbox lewat [pendaftaran mandiri](/en/blog/agent-self-signup-and-claim). Cara kerja cakupannya:

| Cakupan | Mengizinkan |
|---|---|
| `read` | `whoami`, daftar workspace, channel, grup, dan postingan, membaca postingan, analitik |
| `write` | Membuat workspace, grup, media, draf postingan, tautan koneksi, permintaan persetujuan, pembatalan |
| `publish` | Penjadwalan, termasuk `create_post` dengan `schedule_at` |

```bash
export SHAGER_API_KEY="shgr_live_your_key_here"
export API="https://app.shager.ai/api/v1"
```

## Panggilan 1: siapa saya?

```bash
curl -s "$API/me" -H "Authorization: Bearer $SHAGER_API_KEY"
```

```json
{ "data": { "organization_id": "...", "organization": "Northwind Agency", "sandbox": false, "scopes": ["read", "write"] } }
```

Kalau `sandbox` bernilai true, penjadwalan dan tautan koneksi diblokir sampai seorang manusia mengklaim kuncinya. Kalau `publish` tidak ada di `scopes`, Anda bisa membuat draf tetapi tidak bisa menjadwalkannya. Mengetahui hal ini sejak awal menghindarkan Anda dari error 403 yang membingungkan di kemudian hari.

## Panggilan 2: pilih atau buat workspace

Satu workspace biasanya mewakili satu klien atau brand.

```bash
curl -s "$API/workspaces" -H "Authorization: Bearer $SHAGER_API_KEY"

curl -s -X POST "$API/workspaces" \
  -H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Summit Physio", "timezone": "Europe/London", "approval_required": true}'
```

Selalu atur `timezone` (nama zona IANA) saat membuat workspace. Waktu jadwal disimpan bersama offset-nya, dan zona workspace menentukan cara Shager menampilkannya kepada manusia. `approval_required: true` berarti postingan harus disetujui klien sebelum bisa dijadwalkan, default yang baik untuk klien baru.

Ekspor ID dari respons agar perintah-perintah berikutnya berjalan:

```bash
export WS="the_workspace_id"
```

## Panggilan 3: daftar channel dan grup

```bash
curl -s "$API/workspaces/$WS/channels" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/groups" -H "Authorization: Bearer $SHAGER_API_KEY"
```

Setiap channel dikembalikan dengan `id`, `network`, `name`, `handle`, `status`, `formats` yang didukung, dan `connected_by_client`. Grup mengembalikan `id`, `name`, dan `channel_ids`. Lewat grup, Anda bisa menyasar empat puluh akun tanpa menulis empat puluh ID; kirim `group_ids` ke `create_post` dan setiap channel aktif di grup itu ikut disertakan.

Kalau workspace belum punya channel, buat tautan koneksi dengan `POST /workspaces/{workspace_id}/connect-links` dan kirimkan ke pemilik akun. Mereka menghubungkan sendiri Facebook, Instagram, YouTube, X, LinkedIn, atau TikTok, tanpa perlu login ke Shager.

## Panggilan 4: unggah media dari URL

```bash
curl -s -X POST "$API/workspaces/$WS/media" \
  -H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "url": "https://cdn.summitphysio.example/video/knee-mobility.mp4",
    "file_name": "knee-mobility.mp4",
    "width": 1080, "height": 1920, "duration_ms": 42000
  }'
```

Shager mengunduh file di sisi server dan mengembalikan `id`, `kind`, `mime_type`, dan `size_bytes`. Untuk Reel, Short, dan story, sertakan `width`, `height`, dan `duration_ms` kalau Anda mengetahuinya. Dengan begitu, Shager bisa memeriksa aturan format setiap platform sebelum postingan dijadwalkan, bukan gagal saat pengiriman.

## Panggilan 5: buat draf dengan caption per akun

Inilah panggilan yang paling penting. Berikut versinya dalam TypeScript dengan `fetch` biasa, termasuk helper kecil yang akan Anda pakai berulang kali:

```typescript
const API = "https://app.shager.ai/api/v1";

async function shager<T>(method: string, path: string, body?: unknown): Promise<T> {
  const res = await fetch(`${API}${path}`, {
    method,
    headers: {
      Authorization: `Bearer ${process.env.SHAGER_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  const json = await res.json();
  if (!res.ok) {
    const err = new Error(`${res.status} ${json.error.code}: ${json.error.message}`);
    (err as any).status = res.status;
    throw err;
  }
  return json.data as T;
}

const WS = process.env.SHAGER_WORKSPACE_ID!;
const mediaId = process.env.SHAGER_MEDIA_ID!; // the id returned by call 4
const channels = await shager<Array<{ id: string; name: string; network: string; status: string }>>(
  "GET", `/workspaces/${WS}/channels`,
);

const post = await shager<{ id: string; status: string }>("POST", `/workspaces/${WS}/posts`, {
  label: "Knee mobility, week 42",
  caption: "Three minutes a day for stiffer knees. Full routine in the video.",
  channel_ids: channels.map((c) => c.id),
  media_ids: [mediaId],
  format: "REEL",
  youtube_title: "3-minute knee mobility routine",
  youtube_privacy: "public",
  per_channel: channels.map((c) => ({
    channel_id: c.id,
    caption: `${c.name}: three minutes a day for stiffer knees. Our physios show the routine.`,
  })),
  cta_url: "https://summitphysio.example/book",
  cta_text: "Book an assessment",
  campaign: "knee-mobility-oct",
  first_comment: "Book an assessment: https://summitphysio.example/book",
  stagger_seconds: [45, 120],
});

console.log(post.id, post.status); // DRAFT
```

Manfaat setiap field:

1. `per_channel` memberi setiap akun caption sendiri. Dalam praktiknya, agenlah yang menulis caption-caption ini; template di atas hanya pengganti untuk langkah itu, dan alasannya ada di [menghindari blokir spam dalam skala besar](/en/blog/avoid-spam-blocks-when-posting-at-scale).
2. `format` diterapkan di platform yang mendukungnya, dan pilihan `SHORT` atau `REEL` ditentukan per platform. `youtube_title` dan `youtube_privacy` hanya berlaku untuk channel YouTube.
3. `cta_url` menghasilkan tautan pendek dan set UTM terpisah per akun, dengan `utm_content` sebagai penanda akun. Di atas inilah [atribusi prospek per akun](/en/blog/utm-per-account-lead-attribution) dibangun.
4. `stagger_seconds` mengatur jeda acak antarakun di platform yang sama. Default-nya `[30, 90]`.

Tanpa `schedule_at`, hasilnya adalah draf. Simpan ID-nya untuk panggilan berikutnya dengan `export POST_ID="the_post_id"`.

## Panggilan 6: persetujuan atau penjadwalan

Kalau workspace mewajibkan persetujuan, kirimkan ke klien. Responsnya menyertakan `approval_url` yang bisa dibuka peninjau tanpa login:

```bash
curl -s -X POST "$API/workspaces/$WS/posts/$POST_ID/approval" \
  -H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
  -d '{"reviewer_name": "Dana Ellis", "reviewer_email": "dana@summitphysio.example", "send_email": true}'
```

Setelah disetujui (atau kalau persetujuan tidak diwajibkan), jadwalkan. Langkah ini memerlukan cakupan `publish`, dan `schedule_at` wajib berformat ISO 8601 dengan offset:

```bash
curl -s -X POST "$API/workspaces/$WS/posts/$POST_ID/schedule" \
  -H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
  -d '{"schedule_at": "2026-10-20T08:30:00+01:00"}'
```

Pada titik ini Shager memvalidasi setiap tujuan terhadap aturan platformnya. Kalau ada akun yang akan menolak postingan, Anda menerima 422 `rejected` beserta alasannya, dan tidak ada yang masuk antrean.

## Panggilan 7: cek status dan klik

```bash
curl -s "$API/workspaces/$WS/posts/$POST_ID" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/posts?status=SCHEDULED&limit=50" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/analytics?from=2026-10-01T00:00:00Z&to=2026-10-31T23:59:59Z" \
  -H "Authorization: Bearer $SHAGER_API_KEY"
```

`get_post` mengembalikan satu baris per tujuan dengan `state`, `dispatch_at`, `published_at`, `url` postingan yang sudah tayang, dan `error` jika ada. Analitik mengembalikan `total_clicks`, `by_account`, dan `by_post`, yang menghitung klik di tautan terlacak Shager tanpa lalu lintas bot. Untuk membatalkan postingan terjadwal yang belum mulai dipublikasikan, gunakan `POST /workspaces/{workspace_id}/posts/{post_id}/cancel`.

## Error mana yang harus ditangani kode Anda?

| Status dan kode | Arti | Yang perlu dilakukan |
|---|---|---|
| 401 `unauthorized` | Header tidak ada atau salah format | Kirim `Authorization: Bearer shgr_...` |
| 403 `forbidden` | Kunci tidak punya cakupan yang diperlukan | Buat draf saja, atau minta `publish` ke manusia |
| 403 `sandbox_unclaimed` | Kunci pendaftaran mandiri yang belum diklaim | Tampilkan tautan klaim kepada manusia |
| 404 `not_found` | ID workspace, postingan, atau channel salah | Ambil ulang daftarnya; ID berlaku per workspace |
| 409 `not_scheduled` | Membatalkan postingan yang tidak terjadwal | Baca status postingan lebih dulu |
| 422 `rejected` | Ada aturan platform yang tidak terpenuhi | Tampilkan pesannya; masalahnya disebutkan di sana |
| 429 `rate_limited` | Lebih dari 120 permintaan per menit per kunci | Tunggu sebentar lalu coba lagi |

Batas laju ini jarang menjadi masalah bagi klien yang dirancang dengan baik. Satu `create_post` bisa mencakup ratusan akun, jadi Anda tidak perlu satu panggilan per akun.

## FAQ

### Apakah ada SDK?

Belum ada yang khusus. Dokumen OpenAPI 3.1 bisa dipakai dengan generator standar kalau Anda ingin klien bertipe, dan API-nya cukup ringkas sehingga helper seperti contoh di atas biasanya sudah cukup. CLI Shager sedang disiapkan.

### Apakah REST dan MCP benar-benar sama?

Ya. Setiap tool MCP sepadan dengan satu operasi REST, dengan nama, input, cakupan, batas laju, dan pencatatan audit yang sama. Pakai REST dari skrip dan layanan, dan MCP dari klien agen. Daftar lengkap tool-nya ada di [halaman agen](/en/agents).

### Bagaimana cara mengirim teks berbeda ke Facebook dan YouTube dalam satu postingan?

Gunakan `per_channel` berisi ID dan caption setiap channel, serta `youtube_title` untuk judul YouTube. Satu objek postingan, banyak tujuan, masing-masing dengan caption, format, dan komentar pertama sendiri kalau diperlukan.

## Langkah berikutnya

Begitu rangkaian ini berjalan mulus secara manual, bungkus menjadi sesuatu yang bisa diulang oleh agen. [Membangun skill Claude untuk Shager](/en/blog/build-a-claude-skill-for-shager) menunjukkan cara mengemas panggilan-panggilan ini beserta aturannya menjadi skill yang bisa dipakai ulang.

---
Source: https://shager.ai/id/blog/shager-rest-api-quickstart
