Kimlik doğrulama
Panelde Ayarlar, API ve webhook'lar bölümünden bir API anahtarı oluşturun. Anahtarlar ss_live_ ile başlar, tek bir çalışma alanına aittir ve belirli projelerle sınırlanabilir. Anahtarı her istekte bearer belirteci olarak gönderin:
curl https://www.amaposta.com/api/v1/me \
-H "Authorization: Bearer ss_live_…"
Yanıt anahtarı, yetki kapsamlarını ve çalışma alanını belirtir. Her anahtarın bir veya daha fazla yetki kapsamı vardır:
| Yetki kapsamı | İzin verir |
|---|---|
content:read | Projeleri, kanalları, gönderileri ve medyayı okuyun. |
content:write | Medya yükleyin, gönderi oluşturun veya düzenleyin. |
posts:publish | İnceleme olmadan planlayın ve yayınlayın. Bu izin olmadan gönderiler, onay kullanan projelerde inceleme kutusuna gider; diğer projelerde taslak olarak kalır. |
Her anahtar dakikada 120 istek yapabilir. Bu sınır aşılırsa rate_limited koduyla 429 alırsınız; biraz bekleyip yeniden deneyin.
Projeler ve kanallar
Gönderiler bir projede bulunur. Anahtarınızın görebildiği projeleri, ardından birinin kanallarını listeleyin. Bir kanalı hedeflemek veya metnini değiştirmek için kanalın kimliği gerekir.
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"
Bir kanalın provider değeri (youtube, instagram, tiktok, x, facebook, custom veya sandbox), status değeri (active, expiring, needs_reconnect, error veya disabled) ve supports alanında desteklediği gönderi türleri bulunur.
Medya yükle
Görseller ve videolar proje başına bir kez yüklenir ve istediğiniz sayıda gönderide kullanılabilir. Yüklemenin üç yolu vardır.
Doğrudan yükleme
Dosyayı, file adlı alanda multipart form verisi olarak gönderin. Birkaç yüz MB'a kadar dosyalar için en uygun yöntemdir.
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-F "[email protected]"
Büyük dosyalar için önceden imzalanmış yükleme
Bir yükleme URL'si isteyin, baytları PUT ile doğrudan depolamaya yükleyin, ardından Amaposta'ya tamamlandığını bildirin.
# 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"
Bir URL'den içe aktarın
Amaposta'ya herkese açık bir URL verin; dosyayı arka planda indirsin. Bu adımı atlayıp gönderiyi oluştururken media_url de iletebilirsiniz.
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"}'
Her yükleme bir medya nesnesi döndürür. Nesnenin status değeri pending'den processing'e, ardından ready'ye (veya bir error ile failed'a) geçer. İşlendikten sonra width, height, duration_ms ve bir küçük resim içerir. GET /api/v1/media/{id} uç noktasını düzenli sorgulayın veya media.ready webhook'unu dinleyin. Döndürülen url imzalıdır ve 12 saat geçerlidir.
Gönderi oluştur
POST /api/v1/projects/{project_id}/posts, her kanal için bir teslimatı olan tek bir gönderi oluşturur. Amaposta bunu platforma göre uyarlar: başlıklar yalnızca başlık alanı olan platformlara gider; hashtag'ler YouTube'da etikete, diğerlerinde metin içi hashtag'e dönüşür.
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
Alanlar
| Alan | Ne yapar? |
|---|---|
kind | text, image veya video. Zorunludur. |
title | Başlık alanı olan platformlar kullanır: YouTube, TikTok fotoğraf gönderileri, Facebook videoları. |
description | Açıklama veya gönderi metni. body, caption ya da text olarak da kabul edilir. |
hashtags | # içeren veya içermeyen bir liste. |
media_id, media_url | Yüklenmiş bir medya kimliği veya Amaposta'nın sizin için indireceği herkese açık bir URL. Görsel ve video gönderileri için gereklidir. |
cover_media_id, cover_url | Platformun desteklediği durumlarda videolar için kapak görseli. |
channels | Paylaşım yapılacak kanal kimlikleri. Bu gönderi türünü destekleyen, projedeki tüm etkin kanalları kullanmak için bu alanı göndermeyin. |
overrides | Kanal kimliğine göre kanala özel değişiklikler: title, description, hashtags ve YouTube'un privacy alanı gibi platform options değerleri. |
schedule | mode, at (ISO 8601 biçiminde bir at ile), now veya bir sonraki boş paylaşım zamanı için queue olabilir. Taslak oluşturmak için bu alanı göndermeyin. |
external_ref | Gönderide ve Özel API teslimatlarında aynen geri döndürülen kendi referansınız. |
metadata | Gönderiyle birlikte saklanan serbest biçimli JSON. Üretilen içeriği işaretlemek için "pipeline" ekleyin; panelde gösterilir ve webhook'lar kaynağı pipeline olarak bildirir. |
Yanıt, her kanal için deliveries içinde bir kayıt dahil, gönderinin kendisidir.
Güvenli yeniden denemeler
Ağlarda istekler kaybolabilir. Gönderi oluştururken bir Idempotency-Key başlığı gönderin; aynı anahtarla yeniden deneme, ikinci bir gönderi oluşturmak yerine ilk denemedeki gönderiyi döndürür. Kendi tarafınızda sabit bir değer kullanın; örneğin iş veya bölüm kimliği. Anahtarlar 200 karaktere kısaltılır.
Planla ve yayınla
POST /api/v1/posts/{post_id}/schedule ile bir taslağı planlayın, hemen yayınlayın, kuyruğa ekleyin veya takvimden kaldırın.
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"}'
atBelirtilen zamanda, iki yıl sonrasına kadar yayınlar.nowHemen yayınlar.queueÖnümüzdeki 12 hafta içinde gönderinin kanalları için bir sonraki boş paylaşım zamanını alır.unscheduleGönderiyi yeniden taslaklara taşır.
Herhangi bir gönderi planlanmadan önce düzenleyicidekiyle aynı kontroller çalışır. Bir kontrol başarısız olursa istek, Planlamadan önce bunu düzeltin: YouTube için başlık gerekiyor.
gibi bir mesajla 400 döndürür. Planlama için posts:publish yetkisi veya onayların açık olduğu bir proje gerekir; ikinci durumda gönderi inceleme kutusunda bekler.
Gönderileri ve teslimatları okuyun
Bir projenin gönderilerini status (virgülle ayrılmış durumlar veya inbox, queue ya da history), from/to aralığı, limit ve offset ile filtreleyerek listeleyin. Yanıt {"items": […], "total": n} biçimindedir.
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"
Bir gönderinin genel bir status değeri (draft, in_review, changes_requested, ready, scheduled, publishing, published, partial veya failed) ve her kanal için bir teslimatı vardır:
"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
}
]
Teslimat durumları pending, scheduled, publishing, processing, published, failed ve cancelled değerleridir. DELETE /api/v1/posts/{post_id} bir gönderiyi kaldırır.
Hatalar
Her hata aynı yapıdadır: sabit bir code, kullanıcılara gösterebileceğiniz bir message ve bazen fields (alan bazında mesajlar) ile bir hint içeren error nesnesi.
{
"error": {
"code": "validation",
"message": "Please fix the highlighted fields.",
"fields": {
"kind": "Use text, image or video."
}
}
}
| Durum | Kod | Anlamı |
|---|---|---|
| 400 | bad_request | İstek, talep edildiği şekilde gerçekleştirilemiyor; örneğin kontrolleri geçemeyen bir gönderiyi planlamak. |
| 401 | unauthorized | API anahtarı eksik, yanlış veya iptal edilmiş. |
| 402 | plan_limit | Çalışma alanının planı buna izin vermiyor; hangi sınır olduğu limit alanında belirtilir. |
| 403 | forbidden | Anahtarda bir yetki kapsamı veya projeye erişim eksik. |
| 404 | not_found | Böyle bir proje, gönderi, medya veya uç nokta yok. |
| 409 | conflict | Değişiklik mevcut durumla çakışıyor; örneğin zaten yayınlanmakta olan bir gönderiyi düzenlemek. |
| 422 | validation | Bir veya daha fazla alan düzeltilmeli; fields alanına bakın. |
| 429 | rate_limited | Bu anahtarla dakikada 120'den fazla istek yapıldı. |
| 502 | provider_error | Bir platform reddetti veya başarısız oldu; ne yapılacağını hint belirtir. |
Webhook'lar
Ayarlar, API ve webhook'lar bölümünde bir uç nokta ekleyin, istediğiniz olayları seçin ve imzalama sırrını kopyalayın. Amaposta her olay için URL'nize JSON içeren bir POST isteği gönderir. 2xx dışındaki yanıtlar veya 15 saniye içinde yanıt alınamaması durumunda istekler giderek uzayan aralıklarla yeniden denenir. Sürekli başarısız olan uç noktalar kapatılır ve yöneticilere bildirilir.
| Olay | Gönderilme zamanı |
|---|---|
post.created | Bir gönderi oluşturuldu (panel veya API) |
post.scheduled | Bir gönderi planlandı |
post.approved | Bir gönderi onaylandı |
post.published | Bir gönderi bir kanalda yayına girdi |
post.failed | Bir gönderi bir kanalda yayınlanamadı |
channel.connected | Bir kanal bağlandı veya yeniden bağlandı |
channel.disconnected | Bir kanalın bağlantısı kesildi |
media.ready | Bir yüklemenin işlenmesi tamamlandı |
media.failed | Bir yükleme işlenemedi |
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=…"
}
}
İmzayı doğrulayın
X-Amaposta-Signature değeri t=<unix seconds>,v1=<hex> biçimindedir. Buradaki v1, ham istek gövdesi üzerinden hesaplanan HMAC_SHA256(secret, t + "." + body) değeridir. Bunu kendiniz hesaplayın, sabit sürede karşılaştırın ve tekrar saldırılarını önlemek için eski zaman damgalarını reddedin.
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", ""))
Özel API kanalları
Bir Özel API kanalı, sizin çalıştırdığınız bir HTTPS uç noktasına yayın yapar: CMS'niz, bir bülten aracı veya Amaposta'nın henüz desteklemediği bir platform. Diğer kanallar gibi takvimde yer alır, kontrollerden ve onaydan geçer, yeniden denenir. Bir gönderi yayınlandığında Amaposta her teslimat için bir POST gönderir:
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- API anahtarınız. Başlık adı ve önek (varsayılan olarak
Bearer) kanalda ayarlanır. Idempotency-Key- Teslimat kimliği. Aynı teslimatın yeniden denenmesinde aynı anahtar gönderilir; böylece zaten yaptığınız işi atlayabilirsiniz.
X-Amaposta-Delivery- Günlükleriniz için tekrar teslimat kimliği.
X-Amaposta-Signature- Kanalın kendi imzalama sırrıyla webhook'lar gibi imzalanır.
Nasıl yanıt verilir?
- 2xxYayınlandı. İsteğe bağlı olarak
{"id": "…", "url": "…"}döndürün; bağlantı gönderide görünür. - 401, 403Anahtar reddedildi. Kanal yeniden bağlanmak üzere işaretlenir ve yöneticilere haber verilir. Geçersiz imza için bu kodları kullanmayın.
- 5xx, 408, 429Geçici. Amaposta giderek uzayan aralıklarla yeniden dener.
- Diğer 4xxGönderi mesajınızla birlikte başarısız olarak işaretlenir; birisi sorunu giderip Yeniden dene'ye basabilir.
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 });
});
Uç noktanız internetten erişilebilir olmalıdır; yönlendirmeler izlenmez. Kanalı bağladığınızda Amaposta, ayarladıysanız sağlık URL'nize GET, aksi hâlde uç noktaya OPTIONS isteği göndererek kontrol eder.
Sandbox kanalları
Sandbox kanalı gerçek bir kanal gibi davranır, ancak Amaposta dışına hiçbir şey çıkmaz. Entegrasyonunuzu uçtan uca geliştirmek ve test etmek için kullanın: gönderiler planlanır, yayına girer, yayınlanır veya başarısız olur ve aynı webhook'ları tetikler. Sandbox kanalları her planda ücretsizdir ve kanal sınırına dahil edilmez.
Eklediğinizde nasıl davranacağını seçin:
- Her zaman başarılı olHer gönderi yayınlanır.
- Ara sıra başarısız olGerçek bir kesintiyi beklemeden hataları ve yeniden denemeleri görün.
- Her zaman başarısız ol
post.failedişleme mantığınızı test edin. - Süresi dolmuş bağlantıErişim süresi dolduğunda yeniden bağlanma uyarılarının ve bağlantılarının nasıl göründüğünü görün.
Platform kuralları
Her kanal türünün kabul ettiği içerikler. Kontroller aynı sınırları kullanır; böylece çoğu sorun yayın sırasında değil, gönderi planlanmadan önce ortaya çıkar.
| Platform | Gönderi | Başlık | Metin | Hashtag'ler | Medya |
|---|---|---|---|---|---|
| YouTube | Video | BaşlıkZorunlu, en fazla 100 karakter | AçıklamaEn fazla 5.000 karakter | Etiket olarak gönderilir, en fazla 60 | MP4, MOV, WebM, AVI, MKV; en fazla 256 GB; 1 sn. ile 12 sa. arası |
| Telefon numarası doğrulanmamış hesaplar en fazla 15 dakikalık video yükleyebilir ve özel küçük resim ayarlayamaz. Her yükleme API kotası tüketir; varsayılan Google kotası uygulama başına günde yaklaşık altı yüklemeye izin verir. | |||||
| Görsel | Başlık yok | AçıklamaEn fazla 2.200 karakter | Metne eklenir, en fazla 30 | JPEG; en fazla 8 MB | |
| Video | Başlık yok | AçıklamaEn fazla 2.200 karakter | Metne eklenir, en fazla 30 | MP4, MOV; en fazla 300 MB; 3 sn. ile 15 dk. arası | |
| Instagram İşletme veya İçerik Üretici hesabı gerektirir. Instagram, hesap başına kayan 24 saatlik dönemde API üzerinden 50 gönderi yayınlamaya izin verir. Instagram'da yalnızca metin içeren gönderiler mümkün değildir. | |||||
| TikTok | Görsel | BaşlıkEn fazla 90 karakter | AçıklamaEn fazla 4.000 karakter | Metne eklenir | JPEG, WebP; en fazla 20 MB |
| Video | Başlık yok | AçıklamaEn fazla 2.200 karakter | Metne eklenir | MP4, MOV, WebM; en fazla 4 GB; 3 sn. ile 10 dk. arası | |
| TikTok denetimini tamamlamamış uygulamaların gönderilerini yalnızca içerik üreticisi görebilir. TikTok kapağı bir video karesinden seçer; özel kapak görselleri desteklenmez. TikTok'ta yalnızca metin içeren gönderiler mümkün değildir. | |||||
| X | Metin | Başlık yok | GönderiZorunlu, en fazla 280 (bağlantılar 23, emojiler 2 sayılır) | Metne eklenir | Yok |
| Görsel | Başlık yok | GönderiEn fazla 280 (bağlantılar 23, emojiler 2 sayılır) | Metne eklenir | JPEG, PNG, WebP, GIF; en fazla 5 MB | |
| Video | Başlık yok | GönderiEn fazla 280 (bağlantılar 23, emojiler 2 sayılır) | Metne eklenir | MP4, MOV; en fazla 512 MB; 0,5 sn. ile 2:20 dk. arası | |
| Kendi X geliştirici uygulamanızı kullanırsanız gönderiler, uygulamanın kullandıkça öde modelindeki API kredilerini tüketir. Hashtag'ler karakter sınırına dahildir. | |||||
| Metin | Başlık yok | GönderiZorunlu, en fazla 63.206 karakter | Metne eklenir | Yok | |
| Görsel | Başlık yok | AçıklamaEn fazla 63.206 karakter | Metne eklenir | JPEG, PNG, GIF, WebP; en fazla 10 MB | |
| Video | BaşlıkEn fazla 255 karakter | AçıklamaEn fazla 63.206 karakter | Metne eklenir | MP4, MOV; en fazla 1 GB; 1 sn. ile 20 dk. arası | |
| Yalnızca Sayfalara yayınlar; API üzerinden kişisel profillerde paylaşım yapılamaz. | |||||
| Özel API | Metin | BaşlıkUzunluk sınırı yok | AçıklamaUzunluk sınırı yok | Etiket olarak gönderilir | Yok |
| Görsel | BaşlıkUzunluk sınırı yok | AçıklamaUzunluk sınırı yok | Etiket olarak gönderilir | JPEG, PNG, WebP, GIF | |
| Video | BaşlıkUzunluk sınırı yok | AçıklamaUzunluk sınırı yok | Etiket olarak gönderilir | MP4, MOV, WebM | |
| Amaposta'dan geldiğini doğrulayabilmeniz için her istek bir HMAC-SHA256 başlığıyla imzalanır. 2xx ve isteğe bağlı JSON {"id": "…", "url": "…"} ile yanıt verin. 408, 429 ve 5xx yanıtları giderek uzayan aralıklarla yeniden denenir; 401/403 kanalı yeniden bağlanması için işaretler; diğer 4xx yanıtları teslimatı başarısız kılar, böylece düzeltip yeniden deneyebilirsiniz. | |||||
| Sandbox | Metin | BaşlıkEn fazla 200 karakter | AçıklamaEn fazla 5.000 karakter | Metne eklenir, en fazla 30 | Yok |
| Görsel | BaşlıkEn fazla 200 karakter | AçıklamaEn fazla 5.000 karakter | Metne eklenir, en fazla 30 | JPEG, PNG, WebP, GIF | |
| Video | BaşlıkEn fazla 200 karakter | AçıklamaEn fazla 5.000 karakter | Metne eklenir, en fazla 30 | MP4, MOV, WebM | |
| Yayınlama kısa bir süre alır; böylece durum değişimini canlı izleyebilirsiniz. | |||||