Publiczne API + n8n
Dla twórców i administratorów klubów, którzy prowadzą treści przez automatyzacje: wyślij post do Amatora z n8n, skryptu albo z każdego narzędzia, które potrafi wysłać zapytanie HTTP.
Co to daje
Jeden endpoint publikuje w Twoim imieniu post tekstowy — w jednym z dwóch miejsc:
- Na Twoim profilu — po prostu pomiń
club_id. - W klubie, którym zarządzasz — podaj jego
club_id. Musisz być właścicielem lub administratorem klubu, tak samo jak przy publikowaniu w imieniu klubu w aplikacji.
Jak zdobyć klucz API
- Otwórz aplikację Amator i przejdź do Ustawienia › Klucze API.
- Stuknij Utwórz i nazwij klucz tak, żeby go potem rozpoznać, np. „n8n”.
- Od razu skopiuj klucz — pokazujemy go tylko raz. Jeśli go zgubisz, unieważnij go i utwórz nowy.
Traktuj klucz jak hasło: każdy, kto go ma, może publikować jako Ty. Każdy klucz możesz w dowolnej chwili unieważnić na tym samym ekranie — zapytania z nim przestaną być przyjmowane.
Endpoint
POST https://api.amator.app/api/v1/public/posts
Wyślij body w formacie JSON, a klucz podaj w nagłówku X-API-KEY (nie Authorization: Bearer).
contentstring — treść posta, od 1 do 2000 znaków. Wymagane.club_iduuid | null — klub, w imieniu którego publikujesz. Opcjonalne — bez niego post trafia na Twój profil.
Post na Twoim profilu
curl -X POST https://api.amator.app/api/v1/public/posts \
-H "X-API-KEY: YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"content":"Training moved to 19:00 tonight"}'Post w imieniu klubu
curl -X POST https://api.amator.app/api/v1/public/posts \
-H "X-API-KEY: YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"content":"Match day! Kick-off at 18:00","club_id":"00000000-0000-0000-0000-000000000000"}'Po udanej publikacji dostajesz 201 i link do posta:
HTTP/1.1 201 Created
{
"success": true,
"data": {
"id": "…",
"destination": "club",
"club_id": "00000000-0000-0000-0000-000000000000",
"created_at": "2026-10-05T18:00:00.000Z",
"url": "https://web.amator.app/posts/…"
},
"requestId": "…"
}Jeden post na godzinę — osobno dla każdego miejsca
Każde miejsce publikacji ma własny godzinny limit: Twój profil to jedno miejsce, a każdy klub to osobne. Limity nigdy się nie sumują — post w jednym miejscu nie zużywa limitu w innym, a wolne miejsce gdzie indziej nie pomoże tam, gdzie limit jest już wykorzystany.
- OK Twój profil i klub A w tej samej godzinie
- OK Kluby A, B i C w tej samej godzinie
- 429 Drugi post w klubie A w ciągu godziny — 429, nawet jeśli profil i pozostałe kluby są wolne
Gdy limit jest wykorzystany, dostajesz 429 z nagłówkiem Retry-After (w sekundach) i szczegółami w body:
HTTP/1.1 429 Too Many Requests
Retry-After: 2400
{
"success": false,
"error": {
"code": "PUBLIC_API_RATE_LIMITED",
"message": "This club already had its post this hour",
"details": {
"destination": "club",
"club_id": "00000000-0000-0000-0000-000000000000",
"retry_after_seconds": 2400,
"next_allowed_at": "2026-10-05T19:00:00.000Z"
}
},
"requestId": "…"
}Zanim znów opublikujesz w tym miejscu, odczekaj co najmniej Retry-After sekund albo do next_allowed_at. Nie ponawiaj zapytań w pętli.
Inne odpowiedzi
- 400 FEED_POST_EMPTYTreść posta jest pusta albo za długa.
- 401 PUBLIC_API_KEY_INVALIDBrak klucza albo klucz jest nieznany lub unieważniony.
- 403 FEED_NOT_A_CAPTAINNie jesteś właścicielem ani administratorem tego klubu.
- 404 FEED_TEAM_NOT_FOUNDNie ma klubu o takim
club_id. - 429 PUBLIC_API_RATE_LIMITEDW tym miejscu był już post w tej godzinie.
- 429 FEED_DAILY_LIMIT_REACHEDWyczerpano dzienny limit 40 postów w feedzie.
Gotowy workflow n8n
Pięć węzłów: ręczny start, węzeł Edit Fields z polami content i club_id, węzeł If sprawdzający, czy club_id jest puste, oraz dwa węzły HTTP Request — jeden publikuje na Twoim profilu, drugi w klubie.
Workflow zaczyna się od ręcznego wyzwalacza, żeby dało się go przetestować od razu po imporcie. Gdy zadziała, zamień Start na to, co naprawdę ma go uruchamiać — Schedule, RSS, formularz — i przypisz jego dane do tych dwóch pól.
{
"name": "Amator — publish a post",
"nodes": [
{
"id": "7b0f3a52-1c6e-4d1b-9a43-5e2f8c1d0a01",
"name": "Start",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
0
],
"parameters": {}
},
{
"id": "7b0f3a52-1c6e-4d1b-9a43-5e2f8c1d0a02",
"name": "Post content",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
220,
0
],
"parameters": {
"mode": "manual",
"assignments": {
"assignments": [
{
"id": "7b0f3a52-1c6e-4d1b-9a43-5e2f8c1d0b01",
"name": "content",
"value": "Hello from n8n! Training moved to 19:00 tonight.",
"type": "string"
},
{
"id": "7b0f3a52-1c6e-4d1b-9a43-5e2f8c1d0b02",
"name": "club_id",
"value": "",
"type": "string"
}
]
},
"options": {}
}
},
{
"id": "7b0f3a52-1c6e-4d1b-9a43-5e2f8c1d0a03",
"name": "Club ID empty?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
440,
0
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose",
"version": 2
},
"conditions": [
{
"id": "7b0f3a52-1c6e-4d1b-9a43-5e2f8c1d0c01",
"leftValue": "={{ $json.club_id }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
}
}
],
"combinator": "and"
},
"looseTypeValidation": true,
"options": {}
}
},
{
"id": "7b0f3a52-1c6e-4d1b-9a43-5e2f8c1d0a04",
"name": "Post to my profile",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
680,
-120
],
"parameters": {
"method": "POST",
"url": "https://api.amator.app/api/v1/public/posts",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-API-KEY",
"value": "YOUR_API_KEY_HERE"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ content: $json.content }) }}",
"options": {}
}
},
{
"id": "7b0f3a52-1c6e-4d1b-9a43-5e2f8c1d0a05",
"name": "Post to club",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
680,
120
],
"parameters": {
"method": "POST",
"url": "https://api.amator.app/api/v1/public/posts",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-API-KEY",
"value": "YOUR_API_KEY_HERE"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ content: $json.content, club_id: $json.club_id }) }}",
"options": {}
}
}
],
"connections": {
"Start": {
"main": [
[
{
"node": "Post content",
"type": "main",
"index": 0
}
]
]
},
"Post content": {
"main": [
[
{
"node": "Club ID empty?",
"type": "main",
"index": 0
}
]
]
},
"Club ID empty?": {
"main": [
[
{
"node": "Post to my profile",
"type": "main",
"index": 0
}
],
[
{
"node": "Post to club",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {},
"pinData": {}
}
Import do n8n
- Skopiuj powyższy JSON albo pobierz plik.
- W n8n przejdź do Workflows, utwórz nowy workflow i wklej skopiowany JSON na pusty obszar (Ctrl/Cmd+V). Plik zaimportujesz z menu ⋯ › Import from File.
- W obu węzłach HTTP Request zamień
YOUR_API_KEY_HEREna swój klucz. Jeszcze lepiej: zapisz go jako dane uwierzytelniające n8n (Header Auth, nazwaX-API-KEY). - W węźle Post content wpisz treść w
content. Zostawclub_idpuste, żeby opublikować na profilu, albo wklej ID klubu, żeby opublikować w jego imieniu. - Kliknij Execute workflow. Węzeł HTTP pokaże odpowiedź — przy sukcesie 201 i
urlposta.