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

  1. Otwórz aplikację Amator i przejdź do Ustawienia › Klucze API.
  2. Stuknij Utwórz i nazwij klucz tak, żeby go potem rozpoznać, np. „n8n”.
  3. 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).

  • content string — treść posta, od 1 do 2000 znaków. Wymagane.
  • club_id uuid | 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_EMPTY
    Treść posta jest pusta albo za długa.
  • 401 PUBLIC_API_KEY_INVALID
    Brak klucza albo klucz jest nieznany lub unieważniony.
  • 403 FEED_NOT_A_CAPTAIN
    Nie jesteś właścicielem ani administratorem tego klubu.
  • 404 FEED_TEAM_NOT_FOUND
    Nie ma klubu o takim club_id.
  • 429 PUBLIC_API_RATE_LIMITED
    W tym miejscu był już post w tej godzinie.
  • 429 FEED_DAILY_LIMIT_REACHED
    Wyczerpano 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

  1. Skopiuj powyższy JSON albo pobierz plik.
  2. 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.
  3. W obu węzłach HTTP Request zamień YOUR_API_KEY_HERE na swój klucz. Jeszcze lepiej: zapisz go jako dane uwierzytelniające n8n (Header Auth, nazwa X-API-KEY).
  4. W węźle Post content wpisz treść w content. Zostaw club_id puste, żeby opublikować na profilu, albo wklej ID klubu, żeby opublikować w jego imieniu.
  5. Kliknij Execute workflow. Węzeł HTTP pokaże odpowiedź — przy sukcesie 201 i url posta.