Autentikasi
Buat kunci API di dasbor melalui Pengaturan, API dan webhook. Kunci diawali ss_live_, milik satu ruang kerja, dan dapat dibatasi ke proyek tertentu. Kirim kunci sebagai token bearer pada setiap permintaan:
curl https://www.amaposta.com/api/v1/me \
-H "Authorization: Bearer ss_live_…"
Respons menyebutkan nama kunci, cakupan izinnya, dan ruang kerja. Setiap kunci memiliki satu atau beberapa cakupan:
| Cakupan izin | Mengizinkan |
|---|---|
content:read | Baca proyek, kanal, postingan, dan media. |
content:write | Unggah media dan buat atau edit postingan. |
posts:publish | Jadwalkan dan terbitkan tanpa peninjauan. Tanpanya, postingan masuk ke kotak peninjauan di proyek yang memakai persetujuan, dan tetap menjadi draf di proyek lainnya. |
Setiap kunci dapat membuat 120 permintaan per menit. Jika terlampaui, Anda menerima 429 dengan kode rate_limited; tunggu sebentar dan coba lagi.
Proyek dan kanal
Postingan berada di proyek. Daftar proyek yang dapat dilihat kunci Anda, lalu kanal dalam salah satunya. Anda memerlukan id kanal untuk menargetkannya atau menimpa teksnya.
curl https://www.amaposta.com/api/v1/projects \
-H "Authorization: Bearer $AMAPOSTA_KEY"
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/channels \
-H "Authorization: Bearer $AMAPOSTA_KEY"
Kanal memiliki provider (youtube, instagram, tiktok, x, facebook, custom atau sandbox), status (active, expiring, needs_reconnect, error atau disabled), serta jenis postingan yang didukung dalam supports.
Unggah media
Gambar dan video diunggah sekali per proyek dan dapat dipakai dalam berapa pun postingan. Ada tiga cara mengunggah.
Unggah langsung
Kirim berkas sebagai data formulir multipart dalam kolom bernama file. Cocok untuk berkas hingga beberapa ratus MB.
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-F "[email protected]"
Unggahan bertanda tangan untuk berkas besar
Minta URL unggahan, kirim byte langsung ke penyimpanan dengan PUT, lalu beri tahu Amaposta bahwa Anda sudah selesai.
# 1. Ask for an upload URL. The response is {"media": { … }, "upload_url": "…"}
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media/uploads \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "batch-142.mp4", "content_type": "video/mp4", "size_bytes": 48213844}'
# 2. Upload the bytes to upload_url
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--upload-file batch-142.mp4
# 3. Finish the upload
curl -X POST https://www.amaposta.com/api/v1/media/$MEDIA_ID/complete \
-H "Authorization: Bearer $AMAPOSTA_KEY"
Impor dari URL
Berikan URL publik kepada Amaposta dan berkas akan diunduh di latar belakang. Anda juga dapat melewati langkah ini dan memberikan media_url saat membuat postingan.
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media/import \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://cdn.example.com/batch-142.mp4"}'
Setiap unggahan mengembalikan objek media. status-nya berubah dari pending ke processing lalu ready (atau failed, dengan error). Setelah diproses, objek memuat width, height, duration_ms, dan gambar mini. Periksa berkala GET /api/v1/media/{id} atau dengarkan webhook media.ready. url yang dikembalikan bertanda tangan dan berlaku selama 12 jam.
Buat postingan
POST /api/v1/projects/{project_id}/posts membuat satu postingan dengan pengiriman untuk setiap kanal. Amaposta menyesuaikannya per platform: judul hanya dikirim ke platform dengan kolom judul, tagar menjadi tag di YouTube dan teks sebaris di tempat lain.
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/posts \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: episode-142" \
-d @- <<'JSON'
{
"kind": "video",
"title": "How we roast a batch in 12 minutes",
"description": "From green beans to first crack. We filmed one batch start to finish.",
"hashtags": ["coffee", "behindthescenes"],
"media_url": "https://cdn.example.com/batch-142.mp4",
"cover_url": "https://cdn.example.com/batch-142-cover.jpg",
"overrides": {
"<x-channel-id>": {
"description": "Batch 142 is out: green beans to first crack in 12 minutes."
},
"<youtube-channel-id>": {
"options": { "privacy": "unlisted" }
}
},
"schedule": { "mode": "queue" },
"external_ref": "episode-142",
"metadata": {
"pipeline": { "name": "nightly-cut", "run": "2026-10-17" }
}
}
JSON
Kolom
| Kolom | Fungsi |
|---|---|
kind | text, image, atau video. Wajib. |
title | Dipakai platform dengan kolom judul: YouTube, postingan foto TikTok, video Facebook. |
description | Keterangan, deskripsi, atau teks postingan. Juga diterima sebagai body, caption, atau text. |
hashtags | Daftar, dengan atau tanpa #. |
media_id, media_url | Id media yang diunggah, atau URL publik yang diunduh Amaposta untuk Anda. Diperlukan untuk postingan gambar dan video. |
cover_media_id, cover_url | Gambar sampul video, jika didukung platform. |
channels | Id kanal tujuan postingan. Abaikan untuk memakai semua kanal aktif di proyek yang mendukung jenis postingan ini. |
overrides | Perubahan per kanal dengan id kanal sebagai kunci: title, description, hashtags, dan options platform, seperti privacy YouTube. |
schedule | mode berupa at (dengan at ISO 8601), now, atau queue untuk slot posting kosong berikutnya. Abaikan untuk membuat draf. |
external_ref | Referensi Anda sendiri, dikembalikan pada postingan dan pengiriman Custom API. |
metadata | JSON bebas yang disimpan bersama postingan. Sertakan "pipeline" untuk menandai konten yang dihasilkan; dasbor menampilkannya dan webhook melaporkan asalnya sebagai pipeline. |
Respons berupa postingan, termasuk satu entri dalam deliveries per kanal.
Percobaan ulang yang aman
Jaringan dapat menggagalkan permintaan. Kirim header Idempotency-Key saat membuat postingan, dan percobaan ulang dengan kunci yang sama mengembalikan postingan dari percobaan pertama alih-alih membuat yang kedua. Gunakan nilai stabil dari pihak Anda, seperti id tugas atau episode. Kunci dipotong menjadi 200 karakter.
Jadwalkan dan terbitkan
Jadwalkan draf, terbitkan sekarang, tambahkan ke antrean, atau hapus dari kalender dengan POST /api/v1/posts/{post_id}/schedule.
curl https://www.amaposta.com/api/v1/posts/$POST_ID/schedule \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-H "Content-Type: application/json" \
-d '{"mode": "at", "at": "2026-10-20T07:00:00Z"}'
atMenerbitkan pada waktu yang diberikan, hingga dua tahun ke depan.nowLangsung menerbitkan.queueMengambil slot posting kosong berikutnya untuk kanal postingan dalam 12 minggu ke depan.unscheduleMengembalikan postingan ke draf.
Sebelum dijadwalkan, pemeriksaan yang sama dengan penyunting dijalankan. Jika ada yang gagal, permintaan mengembalikan 400 dengan pesan seperti Perbaiki sebelum menjadwalkan: YouTube memerlukan judul.
Penjadwalan memerlukan cakupan posts:publish, atau proyek dengan persetujuan aktif, yang membuat postingan menunggu di kotak peninjauan.
Baca postingan dan pengiriman
Daftar postingan proyek, difilter menurut status (status dipisahkan koma, atau inbox, queue, atau history), rentang from/to, limit, dan offset. Respons berupa {"items": […], "total": n}.
curl "https://www.amaposta.com/api/v1/projects/$PROJECT_ID/posts?status=queue" \
-H "Authorization: Bearer $AMAPOSTA_KEY"
curl https://www.amaposta.com/api/v1/posts/$POST_ID \
-H "Authorization: Bearer $AMAPOSTA_KEY"
Postingan memiliki status keseluruhan (draft, in_review, changes_requested, ready, scheduled, publishing, published, partial atau failed) dan satu pengiriman per kanal:
"deliveries": [
{
"id": "0192b7d4-…",
"channel_id": "0192b7a1-…",
"status": "published",
"url": "https://www.youtube.com/watch?v=…",
"error": null,
"published_at": "2026-10-20T07:00:41Z"
},
{
"id": "0192b7d4-…",
"channel_id": "0192b7a9-…",
"status": "failed",
"url": null,
"error": {
"code": "endpoint_unavailable",
"message": "Your endpoint returned 503 Service Unavailable",
"hint": "Amaposta will retry with backoff."
},
"published_at": null
}
]
Status pengiriman adalah pending, scheduled, publishing, processing, published, failed, dan cancelled. DELETE /api/v1/posts/{post_id} menghapus postingan.
Kesalahan
Semua kesalahan memiliki struktur yang sama: objek error dengan code stabil, message yang dapat ditampilkan kepada pengguna, dan terkadang fields (pesan per kolom) serta hint.
{
"error": {
"code": "validation",
"message": "Please fix the highlighted fields.",
"fields": {
"kind": "Use text, image or video."
}
}
}
| Status | Kode | Arti |
|---|---|---|
| 400 | bad_request | Permintaan tidak dapat dijalankan sesuai instruksi, seperti menjadwalkan postingan yang gagal pemeriksaan. |
| 401 | unauthorized | Kunci API tidak ada, salah, atau dicabut. |
| 402 | plan_limit | Paket ruang kerja tidak mengizinkannya; limit menyebutkan batasnya. |
| 403 | forbidden | Kunci tidak memiliki cakupan izin atau akses ke proyek. |
| 404 | not_found | Proyek, postingan, media, atau endpoint tidak ditemukan. |
| 409 | conflict | Perubahan bertentangan dengan status saat ini, seperti mengedit postingan yang sedang diterbitkan. |
| 422 | validation | Satu atau beberapa kolom perlu diperbaiki; lihat fields. |
| 429 | rate_limited | Lebih dari 120 permintaan per menit pada kunci ini. |
| 502 | provider_error | Platform menolak atau gagal; hint menjelaskan tindakan yang perlu dilakukan. |
Webhook
Tambahkan endpoint di Pengaturan, API dan webhook, pilih peristiwa yang diinginkan dan salin rahasia penandatanganannya. Amaposta mengirim JSON melalui POST ke URL Anda untuk setiap peristiwa. Respons selain 2xx, atau tanpa jawaban dalam 15 detik, dicoba ulang dengan jeda bertahap. Endpoint yang terus gagal dinonaktifkan dengan pemberitahuan kepada admin.
| Peristiwa | Dikirim saat |
|---|---|
post.created | Postingan dibuat (dasbor atau API) |
post.scheduled | Postingan dijadwalkan |
post.approved | Postingan disetujui |
post.published | Postingan tayang di kanal |
post.failed | Postingan gagal diterbitkan di kanal |
channel.connected | Kanal dihubungkan atau dihubungkan ulang |
channel.disconnected | Koneksi kanal terputus |
media.ready | Unggahan selesai diproses |
media.failed | Unggahan tidak dapat diproses |
POST /your/webhook HTTP/1.1
Content-Type: application/json
User-Agent: Amaposta-Webhooks/1.0
X-Amaposta-Event: post.published
X-Amaposta-Event-Id: 0192b7e0-…
X-Amaposta-Signature: t=1792479641,v1=5f2b0c…
{
"id": "0192b7e0-…",
"type": "post.published",
"created_at": "2026-10-20T07:00:41Z",
"project_id": "0192a3f1-…",
"data": {
"post_id": "0192b7c8-…",
"delivery_id": "0192b7d4-…",
"channel_id": "0192b7a1-…",
"provider": "youtube",
"external_id": "…",
"url": "https://www.youtube.com/watch?v=…"
}
}
Verifikasi tanda tangan
X-Amaposta-Signature adalah t=<unix seconds>,v1=<hex>, dengan v1 berupa HMAC_SHA256(secret, t + "." + body) atas isi permintaan mentah. Hitung sendiri, bandingkan dalam waktu konstan, dan tolak stempel waktu lama untuk mencegah pengulangan.
import crypto from "node:crypto";
// rawBody: the request body exactly as received (string or Buffer).
export function verifySignature(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest();
const given = Buffer.from(parts.v1 ?? "", "hex");
return given.length === expected.length && crypto.timingSafeEqual(given, expected);
}
import hashlib
import hmac
import time
def verify_signature(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t = int(parts.get("t", "0"))
if abs(time.time() - t) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))
Kanal Custom API
Kanal Custom API menerbitkan ke endpoint HTTPS yang Anda jalankan: CMS, alat buletin, atau platform yang belum didukung Amaposta. Kanal tampil di kalender serta mendapat pemeriksaan, persetujuan, dan percobaan ulang seperti kanal lain. Saat postingan dikirim, Amaposta mengirim satu POST per pengiriman:
POST /amaposta/publish HTTP/1.1
Authorization: Bearer <your API key>
Content-Type: application/json
Idempotency-Key: 0192b7d4-…
X-Amaposta-Delivery: 0192b7d4-…
X-Amaposta-Signature: t=1792479600,v1=9ac41e…
{
"id": "0192b7d4-…",
"type": "post.publish",
"created_at": "2026-10-20T07:00:00Z",
"content": {
"kind": "video",
"title": "How we roast a batch in 12 minutes",
"text": "From green beans to first crack. We filmed one batch start to finish.",
"hashtags": ["coffee", "behindthescenes"],
"media": {
"url": "https://…",
"content_type": "video/mp4",
"size_bytes": 48213844,
"width": 1080,
"height": 1920,
"duration_ms": 58000,
"filename": "batch-142.mp4"
},
"cover": null,
"options": {}
},
"post": {
"id": "0192b7c8-…",
"external_ref": "episode-142",
"scheduled_at": "2026-10-20T07:00:00Z",
"metadata": {
"pipeline": { "name": "nightly-cut" }
}
},
"project": { "id": "0192a3f1-…", "name": "Spring launch" },
"channel": { "id": "0192b7a9-…", "name": "api.example.com" }
}
Authorization- Kunci API Anda. Nama header dan awalan (
Bearersecara bawaan) diatur pada kanal. Idempotency-Key- Id pengiriman. Percobaan ulang pengiriman yang sama mengirim kunci yang sama, sehingga Anda dapat melewati pekerjaan yang sudah dilakukan.
X-Amaposta-Delivery- Id pengiriman lagi, untuk log Anda.
X-Amaposta-Signature- Ditandatangani seperti webhook, dengan rahasia penandatanganan kanal sendiri.
Cara membalas
- 2xxDiterbitkan. Opsional, kembalikan
{"id": "…", "url": "…"}dan tautan muncul pada postingan. - 401, 403Kunci ditolak. Kanal ditandai perlu koneksi ulang dan admin diberi tahu. Jangan gunakan ini untuk tanda tangan yang salah.
- 5xx, 408, 429Sementara. Amaposta mencoba ulang dengan jeda bertahap.
- 4xx lainnyaPostingan ditandai gagal beserta pesan Anda, dan pengguna dapat memperbaikinya lalu menekan Coba lagi.
app.post("/amaposta/publish", express.raw({ type: "application/json" }), async (req, res) => {
const signature = req.get("X-Amaposta-Signature") ?? "";
if (!verifySignature(req.body, signature, process.env.AMAPOSTA_SIGNING_SECRET)) {
return res.status(400).json({ message: "Bad signature" });
}
const delivery = JSON.parse(req.body);
const item = await publishToYourSystem(delivery.content, req.get("Idempotency-Key"));
res.json({ id: item.id, url: item.url });
});
Endpoint harus dapat dijangkau dari internet; pengalihan tidak diikuti. Saat menghubungkan kanal, Amaposta memeriksanya melalui GET ke URL kesehatan jika diatur, atau permintaan OPTIONS ke endpoint.
Kanal Sandbox
Kanal sandbox berperilaku seperti kanal asli, tetapi tidak ada yang keluar dari Amaposta. Gunakan untuk membangun dan menguji integrasi menyeluruh: postingan dijadwalkan, tayang, terbit atau gagal, dan memicu webhook yang sama. Kanal Sandbox gratis pada semua paket dan tidak dihitung dalam batas kanal.
Pilih perilakunya saat menambahkan:
- Selalu berhasilSetiap postingan diterbitkan.
- Sesekali gagalLihat kegagalan dan percobaan ulang tanpa menunggu gangguan nyata.
- Selalu gagalUji penanganan
post.failedAnda. - Koneksi kedaluwarsaLihat tampilan peringatan dan tautan koneksi ulang saat akses berakhir.
Aturan platform
Yang diterima setiap jenis kanal. Pemeriksaan memakai batas yang sama, sehingga sebagian besar masalah muncul sebelum penjadwalan postingan, bukan saat penerbitan.
| Platform | Postingan | Judul | Teks | Tagar | Media |
|---|---|---|---|---|---|
| YouTube | Video | JudulWajib, maksimal 100 karakter | DeskripsiMaksimal 5.000 karakter | Dikirim sebagai tag, maksimal 60 | MP4, MOV, WebM, AVI, MKV; maksimal 256 GB; 1 dtk hingga 12 jam |
| Akun yang belum memverifikasi nomor telepon dapat mengunggah maksimal 15 menit dan tidak dapat menetapkan gambar mini kustom. Setiap unggahan memakai kuota API; kuota bawaan Google mengizinkan sekitar enam unggahan per hari per aplikasi. | |||||
| Gambar | Tanpa judul | KeteranganMaksimal 2.200 karakter | Ditambahkan ke teks, maksimal 30 | JPEG; maksimal 8 MB | |
| Video | Tanpa judul | KeteranganMaksimal 2.200 karakter | Ditambahkan ke teks, maksimal 30 | MP4, MOV; maksimal 300 MB; 3 dtk hingga 15 min | |
| Memerlukan akun Instagram Business atau Creator. Instagram mengizinkan 50 postingan melalui API per akun dalam rentang 24 jam berjalan. Postingan teks saja tidak dapat dibuat di Instagram. | |||||
| TikTok | Gambar | JudulMaksimal 90 karakter | DeskripsiMaksimal 4.000 karakter | Ditambahkan ke teks | JPEG, WebP; maksimal 20 MB |
| Video | Tanpa judul | KeteranganMaksimal 2.200 karakter | Ditambahkan ke teks | MP4, MOV, WebM; maksimal 4 GB; 3 dtk hingga 10 min | |
| Postingan dari aplikasi yang belum menyelesaikan audit TikTok hanya terlihat oleh pembuatnya. TikTok memilih sampul dari bingkai video; gambar sampul kustom tidak didukung. Postingan teks saja tidak dapat dibuat di TikTok. | |||||
| X | Teks | Tanpa judul | PostinganWajib, maksimal 280 (tautan dihitung 23, emoji 2) | Ditambahkan ke teks | Tidak ada |
| Gambar | Tanpa judul | PostinganMaksimal 280 (tautan dihitung 23, emoji 2) | Ditambahkan ke teks | JPEG, PNG, WebP, GIF; maksimal 5 MB | |
| Video | Tanpa judul | PostinganMaksimal 280 (tautan dihitung 23, emoji 2) | Ditambahkan ke teks | MP4, MOV; maksimal 512 MB; 0,5 dtk hingga 2:20 min | |
| Dengan aplikasi pengembang X sendiri, postingan memakai kredit API sesuai penggunaannya. Tagar dihitung dalam batas karakter. | |||||
| Teks | Tanpa judul | PostinganWajib, maksimal 63.206 karakter | Ditambahkan ke teks | Tidak ada | |
| Gambar | Tanpa judul | KeteranganMaksimal 63.206 karakter | Ditambahkan ke teks | JPEG, PNG, GIF, WebP; maksimal 10 MB | |
| Video | JudulMaksimal 255 karakter | DeskripsiMaksimal 63.206 karakter | Ditambahkan ke teks | MP4, MOV; maksimal 1 GB; 1 dtk hingga 20 min | |
| Hanya menerbitkan ke Halaman; API tidak dapat memposting ke profil pribadi. | |||||
| Custom API | Teks | JudulTanpa batas panjang | DeskripsiTanpa batas panjang | Dikirim sebagai tag | Tidak ada |
| Gambar | JudulTanpa batas panjang | DeskripsiTanpa batas panjang | Dikirim sebagai tag | JPEG, PNG, WebP, GIF | |
| Video | JudulTanpa batas panjang | DeskripsiTanpa batas panjang | Dikirim sebagai tag | MP4, MOV, WebM | |
| Setiap permintaan ditandatangani dengan header HMAC-SHA256 agar dapat diverifikasi berasal dari Amaposta. Balas dengan 2xx dan JSON opsional {"id": "…", "url": "…"}. Respons 408, 429, dan 5xx dicoba ulang dengan jeda bertahap; 401/403 menandai kanal untuk koneksi ulang; 4xx lainnya menggagalkan pengiriman agar dapat diperbaiki dan dicoba ulang. | |||||
| Sandbox | Teks | JudulMaksimal 200 karakter | DeskripsiMaksimal 5.000 karakter | Ditambahkan ke teks, maksimal 30 | Tidak ada |
| Gambar | JudulMaksimal 200 karakter | DeskripsiMaksimal 5.000 karakter | Ditambahkan ke teks, maksimal 30 | JPEG, PNG, WebP, GIF | |
| Video | JudulMaksimal 200 karakter | DeskripsiMaksimal 5.000 karakter | Ditambahkan ke teks, maksimal 30 | MP4, MOV, WebM | |
| Penerbitan memerlukan waktu sebentar agar Anda dapat melihat perubahan status secara langsung. | |||||