Uwierzytelnianie
Utwórz klucz API w panelu w Ustawieniach, w sekcji API i webhooki. Klucze zaczynają się od ss_live_, należą do jednej przestrzeni roboczej i mogą być ograniczone do wybranych projektów. Wysyłaj klucz jako token Bearer w każdym żądaniu:
curl https://www.amaposta.com/api/v1/me \
-H "Authorization: Bearer ss_live_…"
Odpowiedź podaje nazwę klucza, jego zakresy uprawnień i przestrzeń roboczą. Każdy klucz ma co najmniej jeden zakres:
| Zakres uprawnień | Zezwala na |
|---|---|
content:read | Odczyt projektów, kanałów, postów i multimediów. |
content:write | Przesyłanie multimediów oraz tworzenie lub edycja postów. |
posts:publish | Planowanie i publikowanie bez weryfikacji. Bez tego uprawnienia posty trafiają do skrzynki weryfikacji w projektach z zatwierdzaniem, a w pozostałych pozostają szkicami. |
Każdy klucz może wykonać 120 żądań na minutę. Po przekroczeniu limitu otrzymasz 429 z kodem rate_limited; odczekaj chwilę i spróbuj ponownie.
Projekty i kanały
Posty należą do projektu. Wyświetl projekty dostępne dla Twojego klucza, a następnie kanały jednego z nich. Identyfikator kanału jest potrzebny, aby wybrać go jako cel lub nadpisać jego tekst.
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"
Kanał ma pola provider (youtube, instagram, tiktok, x, facebook, custom lub sandbox), status (active, expiring, needs_reconnect, error lub disabled) oraz obsługiwane rodzaje postów w polu supports.
Prześlij multimedia
Obrazy i filmy przesyła się raz do projektu, a następnie można ich używać w dowolnej liczbie postów. Są trzy sposoby ich dodawania.
Przesyłanie bezpośrednie
Wyślij plik jako dane formularza multipart w polu o nazwie file. Najlepiej sprawdza się przy plikach do kilkuset MB.
curl https://www.amaposta.com/api/v1/projects/$PROJECT_ID/media \
-H "Authorization: Bearer $AMAPOSTA_KEY" \
-F "[email protected]"
Podpisany adres przesyłania dużych plików
Poproś o adres URL do przesyłania, wyślij bajty bezpośrednio do magazynu metodą PUT, a potem powiadom Amaposta o zakończeniu.
# 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"
Importuj z adresu URL
Podaj Amaposta publiczny adres URL, a pobierze plik w tle. Możesz też pominąć ten krok i podać media_url podczas tworzenia posta.
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"}'
Każde przesłanie zwraca obiekt multimedialny. Jego status zmienia się z pending na processing, a następnie ready (lub failed, z polem error). Po przetworzeniu zawiera pola width, height, duration_ms i miniaturę. Odpytuj GET /api/v1/media/{id} lub nasłuchuj webhooka media.ready. Zwracany url jest podpisany i ważny przez 12 godzin.
Utwórz post
POST /api/v1/projects/{project_id}/posts tworzy jeden post z osobną wysyłką dla każdego kanału. Amaposta dostosowuje go do platformy: tytuły trafiają tylko tam, gdzie jest pole tytułu, a hashtagi stają się tagami w YouTube i częścią tekstu na pozostałych platformach.
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
Pola
| Pole | Co robi |
|---|---|
kind | text, image lub video. Wymagane. |
title | Używane przez platformy z polem tytułu: YouTube, posty ze zdjęciami TikTok, filmy Facebook. |
description | Podpis, opis lub tekst posta. Akceptowane również jako body, caption lub text. |
hashtags | Lista, ze znakiem # lub bez niego. |
media_id, media_url | Identyfikator przesłanego pliku multimedialnego lub publiczny adres URL, z którego Amaposta go pobierze. Wymagane w postach z obrazem lub filmem. |
cover_media_id, cover_url | Okładka filmu, jeśli platforma ją obsługuje. |
channels | Identyfikatory kanałów docelowych. Pomiń to pole, aby użyć każdego aktywnego kanału w projekcie, który obsługuje ten rodzaj posta. |
overrides | Zmiany dla poszczególnych kanałów, z identyfikatorem kanału jako kluczem: title, description, hashtags i ustawienia platformy options, np. privacy dla YouTube. |
schedule | mode to at (z polem at w formacie ISO 8601), now lub queue, aby wybrać następny wolny termin publikacji. Pomiń to pole, aby utworzyć szkic. |
external_ref | Twój własny identyfikator referencyjny, zwracany w poście i wysyłkach Własne API. |
metadata | Dowolne dane JSON zapisywane z postem. Dodaj "pipeline", aby oznaczyć wygenerowane treści; panel wyświetli to oznaczenie, a webhooki podadzą źródło jako pipeline. |
Odpowiedź zawiera post, w tym po jednym wpisie w deliveries na kanał.
Bezpieczne ponawianie prób
W sieci żądania czasem giną. Podczas tworzenia posta wyślij nagłówek Idempotency-Key, a ponowienie z tym samym kluczem zwróci post z pierwszej próby zamiast tworzyć kolejny. Użyj stałej wartości ze swojego systemu, np. identyfikatora zadania lub odcinka. Klucze są przycinane do 200 znaków.
Planowanie i publikowanie
Zaplanuj szkic, opublikuj go teraz, dodaj do kolejki lub usuń z kalendarza za pomocą 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"}'
atPublikuje w podanym terminie, z wyprzedzeniem do dwóch lat.nowPublikuje od razu.queueWybiera następny wolny termin publikacji dla kanałów posta w ciągu najbliższych 12 tygodni.unschedulePrzenosi post z powrotem do szkiców.
Przed zaplanowaniem czegokolwiek wykonywane są te same kontrole co w edytorze. Jeśli któraś się nie powiedzie, żądanie zwraca 400 z komunikatem takim jak Popraw to przed zaplanowaniem: YouTube wymaga tytułu.
Planowanie wymaga uprawnienia posts:publish lub projektu z włączonym zatwierdzaniem — wtedy post czeka w skrzynce weryfikacji.
Odczyt postów i wysyłek
Wyświetl posty projektu, filtrując według status (statusy oddzielone przecinkami lub inbox, queue albo history), zakresu from/to, limit i offset. Odpowiedź ma postać {"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"
Post ma ogólny status (draft, in_review, changes_requested, ready, scheduled, publishing, published, partial lub failed) i po jednej wysyłce na kanał:
"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
}
]
Statusy wysyłki to pending, scheduled, publishing, processing, published, failed i cancelled. DELETE /api/v1/posts/{post_id} usuwa post.
Błędy
Każdy błąd ma tę samą strukturę: obiekt error ze stałym polem code, komunikatem message do pokazania użytkownikom i czasami polami fields (komunikaty dla poszczególnych pól) oraz hint.
{
"error": {
"code": "validation",
"message": "Please fix the highlighted fields.",
"fields": {
"kind": "Use text, image or video."
}
}
}
| Status | Kod | Znaczenie |
|---|---|---|
| 400 | bad_request | Nie można wykonać żądania w podanej formie, np. zaplanować posta, który nie przechodzi kontroli. |
| 401 | unauthorized | Brakuje klucza API, jest nieprawidłowy lub został unieważniony. |
| 402 | plan_limit | Plan przestrzeni roboczej na to nie pozwala; pole limit wskazuje, który limit został osiągnięty. |
| 403 | forbidden | Klucz nie ma wymaganego uprawnienia lub dostępu do projektu. |
| 404 | not_found | Nie ma takiego projektu, posta, pliku multimedialnego ani punktu końcowego. |
| 409 | conflict | Zmiana koliduje z obecnym stanem, np. edycja posta, którego publikowanie już trwa. |
| 422 | validation | Co najmniej jedno pole wymaga poprawy; zobacz fields. |
| 429 | rate_limited | Ponad 120 żądań na minutę dla tego klucza. |
| 502 | provider_error | Platforma odmówiła lub wystąpił na niej błąd; pole hint podpowiada, co zrobić. |
Webhooki
Dodaj punkt końcowy w Ustawieniach, w sekcji API i webhooki, wybierz zdarzenia i skopiuj jego sekret podpisu. Amaposta wysyła dla każdego zdarzenia żądanie POST z danymi JSON na Twój adres URL. Każda odpowiedź inna niż 2xx lub brak odpowiedzi przez 15 sekund powoduje ponowienie z rosnącym odstępem. Punkty końcowe, w których błędy się powtarzają, są wyłączane, a administratorzy otrzymują powiadomienie.
| Zdarzenie | Wysyłane, gdy |
|---|---|
post.created | Utworzono post (w panelu lub przez API) |
post.scheduled | Zaplanowano publikację posta |
post.approved | Post został zatwierdzony |
post.published | Post został opublikowany w kanale |
post.failed | Nie udało się opublikować posta w kanale |
channel.connected | Kanał został połączony lub połączony ponownie |
channel.disconnected | Kanał utracił połączenie |
media.ready | Zakończono przetwarzanie przesłanego pliku |
media.failed | Nie udało się przetworzyć przesłanego pliku |
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=…"
}
}
Sprawdź podpis
X-Amaposta-Signature ma postać t=<unix seconds>,v1=<hex>, gdzie v1 to HMAC_SHA256(secret, t + "." + body) obliczony dla surowej treści żądania. Oblicz go samodzielnie, porównaj w stałym czasie i odrzucaj stare znaczniki czasu, aby zapobiec powtórzeniom żądań.
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", ""))
Kanały Własne API
Kanał Własne API publikuje w utrzymywanym przez Ciebie punkcie końcowym HTTPS: w Twoim CMS, narzędziu do newsletterów lub na platformie, której Amaposta jeszcze nie obsługuje. Pojawia się w kalendarzu i podlega kontrolom, zatwierdzaniu i ponownym próbom tak jak każdy inny kanał. Gdy nadchodzi czas publikacji, Amaposta wysyła jedno żądanie POST na każdą wysyłkę:
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- Twój klucz API. Nazwa nagłówka i prefiks (domyślnie
Bearer) są ustawiane w kanale. Idempotency-Key- Identyfikator wysyłki. Ponowienie tej samej wysyłki wysyła ten sam klucz, więc możesz pominąć już wykonaną pracę.
X-Amaposta-Delivery- Ponownie identyfikator wysyłki, do Twoich dzienników.
X-Amaposta-Signature- Podpisywane tak jak webhooki, własnym sekretem podpisu kanału.
Jak odpowiadać
- 2xxOpublikowano. Opcjonalnie zwróć
{"id": "…", "url": "…"}, a link pojawi się przy poście. - 401, 403Klucz został odrzucony. Kanał zostaje oznaczony jako wymagający ponownego połączenia, a administratorzy otrzymują powiadomienie. Nie używaj tych kodów przy nieprawidłowym podpisie.
- 5xx, 408, 429Błąd tymczasowy. Amaposta ponawia próby z rosnącym odstępem.
- Inne 4xxPost otrzymuje status niepowodzenia z Twoim komunikatem, a ktoś może go poprawić i nacisnąć Ponów.
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 });
});
Twój punkt końcowy musi być dostępny z internetu; przekierowania nie są śledzone. Podczas łączenia kanału Amaposta sprawdza go żądaniem GET do adresu kontroli stanu, jeśli został ustawiony, lub żądaniem OPTIONS do punktu końcowego.
Kanały Sandbox
Kanał testowy zachowuje się jak prawdziwy, ale nic nie opuszcza Amaposta. Zbuduj i przetestuj w nim integrację od początku do końca: posty są planowane, trafiają na antenę, publikują się lub kończą błędem i wywołują te same webhooki. Kanały testowe są bezpłatne w każdym planie i nie wliczają się do limitów kanałów.
Wybierz zachowanie po dodaniu:
- Zawsze kończ powodzeniemKażdy post zostaje opublikowany.
- Czasem kończ błędemZobacz błędy i ponowne próby bez czekania na prawdziwą awarię.
- Zawsze kończ błędemPrzetestuj obsługę zdarzenia
post.failed. - Połączenie wygasłoSprawdź wygląd alertów i linków do ponownego połączenia po wygaśnięciu dostępu.
Reguły platformy
Wymagania poszczególnych typów kanałów. Kontrole używają tych samych limitów, więc większość problemów pojawia się przed zaplanowaniem posta, a nie dopiero przy publikacji.
| Platforma | Post | Tytuł | Tekst | Hashtagi | Multimedia |
|---|---|---|---|---|---|
| YouTube | Film | TytułWymagane, limit znaków: 100 | OpisLimit znaków: 5000 | Wysyłane jako tagi, maksymalnie 60 | MP4, MOV, WebM, AVI, MKV; do 256 GB; Od 1 s do 12 godz. |
| Konta bez zweryfikowanego numeru telefonu mogą przesyłać filmy do 15 minut i nie mogą ustawiać własnych miniatur. Każde przesłanie zużywa limit API; domyślny limit Google pozwala na około sześć przesłań dziennie na aplikację. | |||||
| Obraz | Brak tytułu | PodpisLimit znaków: 2200 | Dodawane do tekstu, maksymalnie 30 | JPEG; do 8 MB | |
| Film | Brak tytułu | PodpisLimit znaków: 2200 | Dodawane do tekstu, maksymalnie 30 | MP4, MOV; do 300 MB; Od 3 s do 15 min | |
| Wymaga konta Instagram Business lub Creator. Instagram pozwala opublikować przez API 50 postów na konto w każdym ruchomym okresie 24 godzin. Na Instagram nie można publikować postów zawierających tylko tekst. | |||||
| TikTok | Obraz | TytułLimit znaków: 90 | OpisLimit znaków: 4000 | Dodawane do tekstu | JPEG, WebP; do 20 MB |
| Film | Brak tytułu | PodpisLimit znaków: 2200 | Dodawane do tekstu | MP4, MOV, WebM; do 4 GB; Od 3 s do 10 min | |
| Posty z aplikacji, które nie przeszły audytu TikTok, są widoczne tylko dla autora. TikTok wybiera okładkę z klatki filmu; własne obrazy okładek nie są obsługiwane. Na TikTok nie można publikować postów zawierających tylko tekst. | |||||
| X | Tekst | Brak tytułu | PostWymagane, do 280 (linki liczą się jako 23 znaki, emoji jako 2) | Dodawane do tekstu | Brak |
| Obraz | Brak tytułu | PostDo 280 (linki liczą się jako 23 znaki, emoji jako 2) | Dodawane do tekstu | JPEG, PNG, WebP, GIF; do 5 MB | |
| Film | Brak tytułu | PostDo 280 (linki liczą się jako 23 znaki, emoji jako 2) | Dodawane do tekstu | MP4, MOV; do 512 MB; Od 0,5 s do 2:20 min | |
| Jeśli używasz własnej aplikacji deweloperskiej X, posty zużywają jej środki na API w modelu płatności za użycie. Hashtagi wliczają się do limitu znaków. | |||||
| Tekst | Brak tytułu | PostWymagane, limit znaków: 63 206 | Dodawane do tekstu | Brak | |
| Obraz | Brak tytułu | PodpisLimit znaków: 63 206 | Dodawane do tekstu | JPEG, PNG, GIF, WebP; do 10 MB | |
| Film | TytułLimit znaków: 255 | OpisLimit znaków: 63 206 | Dodawane do tekstu | MP4, MOV; do 1 GB; Od 1 s do 20 min | |
| Publikuje tylko na stronach; API nie pozwala publikować w profilach osobistych. | |||||
| Własne API | Tekst | TytułBez limitu długości | OpisBez limitu długości | Wysyłane jako tagi | Brak |
| Obraz | TytułBez limitu długości | OpisBez limitu długości | Wysyłane jako tagi | JPEG, PNG, WebP, GIF | |
| Film | TytułBez limitu długości | OpisBez limitu długości | Wysyłane jako tagi | MP4, MOV, WebM | |
| Każde żądanie jest podpisane nagłówkiem HMAC-SHA256, aby można było sprawdzić, czy pochodzi z Amaposta. Odpowiedz kodem 2xx i opcjonalnymi danymi JSON {"id": "…", "url": "…"}. Odpowiedzi 408, 429 i 5xx powodują ponowienie z rosnącym odstępem; 401/403 oznaczają kanał jako wymagający ponownego połączenia; inne 4xx kończą wysyłkę błędem, aby można było rozwiązać problem i spróbować ponownie. | |||||
| Sandbox | Tekst | TytułLimit znaków: 200 | OpisLimit znaków: 5000 | Dodawane do tekstu, maksymalnie 30 | Brak |
| Obraz | TytułLimit znaków: 200 | OpisLimit znaków: 5000 | Dodawane do tekstu, maksymalnie 30 | JPEG, PNG, WebP, GIF | |
| Film | TytułLimit znaków: 200 | OpisLimit znaków: 5000 | Dodawane do tekstu, maksymalnie 30 | MP4, MOV, WebM | |
| Publikowanie zajmuje chwilę, aby można było obserwować zmianę statusu na żywo. | |||||