DOKUMENTACJA API

API platformy Treści Online

Integruj swój sklep, system płatności lub CRM z platformą kursową tresci.online. Nadawaj i odbieraj dostępy do kursów i audiobooków, rejestruj zamówienia oraz sprawdzaj zapisy uczestników po adresie e-mail.

Wprowadzenie

API platformy Treści Online to interfejs typu server-to-server do programowego zarządzania dostępami uczestników. Najczęściej spina zewnętrzny sklep lub system płatności (np. SalesCRM) z platformą kursową — po opłaceniu zamówienia automatycznie nadaje kupującemu dostęp do kursu lub audiobooka, a po zwrocie go odbiera.

Base URL
https://{subdomena}.tresci.online/api/

{subdomena} to subdomena Twojego konta na platformie. Środowisko testowe (beta) działa pod https://{subdomena}.beta.tresci.online/api/. Połączenie sprawdzisz wywołaniem GET /api/test (zwraca 200 przy poprawnym kluczu).

Klucz API jest powiązany z jednym kontem (tenantem). Każde żądanie widzi i modyfikuje wyłącznie dane tego konta — nigdy innych kont ani panelu administracyjnego.

Autoryzacja

Każde żądanie wymaga nagłówka X-API-KEY z kluczem konta. Klucz wygenerujesz i w razie potrzeby zregenerujesz w panelu platformy: Ustawienia → API. Regeneracja klucza natychmiast unieważnia poprzedni.

Opcjonalnie, jeśli żądanie zawiera nagłówek Referer (np. wywołania z przeglądarki), jego domena musi znajdować się na liście dozwolonych domen konta — w przeciwnym razie zwracane jest 401. Wywołania server-side (bez Referer) wymagają wyłącznie poprawnego klucza.

Przykład
curl -H "X-API-KEY: twoj-klucz-api" \
  https://twoja-subdomena.tresci.online/api/courses

Trzymaj klucz po stronie serwera. Nie umieszczaj go w kodzie front-endu ani w repozytorium. Klucz daje pełny dostęp do danych konta przez API.

Format odpowiedzi

Wszystkie odpowiedzi są w formacie JSON. Listy zwracane są jako obiekt z kluczem zasobu (np. courses) — bez koperty data/meta i bez paginacji. Operacje nadawania i odbierania dostępu zwracają 204 No Content.

Lista (sukces)
{
  "courses": [
    { "id": "0a1b2c3d-...", "title": "Kurs pszczelarstwa" }
  ]
}
Błąd walidacji (nadawanie/odbieranie dostępu)
{
  "invalid_subscriptions": [
    { "course_id": "nieistniejace-id", "email": "zly-email" }
  ]
}

Błąd walidacji zwracany jest ze statusem 400. Lista invalid_subscriptions (lub invalid_unsubscriptions) zawiera wpisy, które nie przeszły walidacji — pozostałe poprawne wpisy nie są wtedy przetwarzane.

Rate Limiting

Ruch do API jest limitowany, aby chronić platformę przed nadużyciem klucza i masowym odpytywaniem.

RegułaLimitLiczone wg
Ogólny100 / minklucz API
Na IP120 / minadres IP
Mutacje (POST/DELETE)30 / minklucz API
Żądania bez klucza5 / 5 minadres IP

Po przekroczeniu limitu otrzymasz 429 Too Many Requests z nagłówkiem Retry-After. Uporczywe wysyłanie żądań bez klucza skutkuje czasową blokadą IP (godzina) i odpowiedzią 403 Forbidden.

Kursy
GET /api/courses

Lista wszystkich aktywnych kursów na koncie.

Przykład odpowiedzi
{
  "courses": [
    { "id": "0a1b2c3d-4e5f-6789-abcd-ef0123456789", "title": "Kurs pszczelarstwa" },
    { "id": "11112222-3333-4444-5555-666677778888", "title": "Miód krok po kroku" }
  ]
}
POST /api/courses/subscribe

Nadaje uczestnikowi (po adresie e-mail) dostęp do kursu. Jeśli konto o danym e-mailu nie istnieje, zostaje utworzone i zaproszone. Operacja jest kolejkowana — dostęp nadawany jest w tle.

Parametry

PoleTypWymaganeOpis
course_iduuidTakID kursu (z GET /api/courses)
emailstringTakE-mail uczestnika
namestringNieImię i nazwisko uczestnika
access_levelintegerNiePoziom dostępu: 0 zwykły (domyślnie), 1 Premium

Poziom dostępu

Sekcja kursu może wymagać podwyższonego poziomu. Uczestnik bez tego poziomu nie widzi jej ani na liście, ani po bezpośrednim adresie lekcji. Pominięcie pola access_level znaczy poziom zwykły, czyli zachowanie sprzed wprowadzenia poziomów.

Poziom może tylko rosnąć. Nadanie zwykłego poziomu komuś, kto ma już Premium, niczego mu nie odbiera. Dzięki temu dokupienie wariantu wyższego obsługuje to samo zapytanie: brakujące lekcje dosypią się same, a dotychczasowy postęp zostaje. Ponowienie tego samego zapytania jest bezpieczne i niczego nie duplikuje.

Odebranie Premium przez to API nie jest możliwe. Robi się to ręcznie w panelu platformy, przy uczestniku kursu.

curl
curl -X POST \
  -H "X-API-KEY: twoj-klucz-api" \
  -H "Content-Type: application/json" \
  -d '{"subscriptions":{"course_id":"0a1b2c3d-...","email":"jan@example.com","name":"Jan Kowalski","access_level":1}}' \
  https://twoja-subdomena.tresci.online/api/courses/subscribe

Sukces → 200 OK. Błąd walidacji → 400 z polem invalid_subscriptions. Wartość access_level spoza dopuszczalnego zakresu odrzuca całą paczkę wpisów.

DELETE /api/courses/unsubscribe

Odbiera uczestnikowi dostęp do kursu.

Parametry

PoleTypWymaganeOpis
course_iduuidTakID kursu
emailstringTakE-mail uczestnika
curl
curl -X DELETE \
  -H "X-API-KEY: twoj-klucz-api" \
  -H "Content-Type: application/json" \
  -d '{"unsubscriptions":{"course_id":"0a1b2c3d-...","email":"jan@example.com"}}' \
  https://twoja-subdomena.tresci.online/api/courses/unsubscribe

Sukces → 204 No Content.

Audiobooki
GET /api/audiobooks

Lista wszystkich aktywnych audiobooków na koncie.

Przykład odpowiedzi
{
  "audiobooks": [
    { "id": "aaaa1111-...", "title": "Pszczoły. Audiobook" }
  ]
}
POST /api/audiobooks/subscribe

Nadaje uczestnikowi dostęp do audiobooka.

Parametry

PoleTypWymaganeOpis
audiobook_iduuidTakID audiobooka (z GET /api/audiobooks)
emailstringTakE-mail uczestnika
namestringNieImię i nazwisko uczestnika
curl
curl -X POST \
  -H "X-API-KEY: twoj-klucz-api" \
  -H "Content-Type: application/json" \
  -d '{"subscriptions":{"audiobook_id":"aaaa1111-...","email":"jan@example.com","name":"Jan Kowalski"}}' \
  https://twoja-subdomena.tresci.online/api/audiobooks/subscribe

Sukces → 204 No Content. Błąd walidacji → 400 z polem invalid_subscriptions.

DELETE /api/audiobooks/unsubscribe

Odbiera uczestnikowi dostęp do audiobooka.

Parametry

PoleTypWymaganeOpis
audiobook_iduuidTakID audiobooka
emailstringTakE-mail uczestnika
curl
curl -X DELETE \
  -H "X-API-KEY: twoj-klucz-api" \
  -H "Content-Type: application/json" \
  -d '{"unsubscriptions":{"audiobook_id":"aaaa1111-...","email":"jan@example.com"}}' \
  https://twoja-subdomena.tresci.online/api/audiobooks/unsubscribe

Sukces → 204 No Content.

Zamówienia
POST /api/orders

Rejestruje zamówienie na platformie. Na jego podstawie kupującemu (po email) nadawane są dostępy do treści wskazanych w ordered_contents. Operacja jest idempotentna względem external_id — ponowne zgłoszenie tego samego zamówienia zwraca 200 zamiast tworzyć duplikat.

Parametry (obiekt order)

PoleTypWymaganeOpis
emailstringTakE-mail kupującego
external_idstringTakID zamówienia w Twoim systemie (klucz idempotencji)
ordinal_numberstringNieNumer zamówienia (do wyświetlenia)
gift_codestringNieKod podarunkowy
ordered_contentsarrayTakPozycje zamówienia — patrz niżej

Pozycja w ordered_contents

PoleTypOpis
product_idstringID produktu w Twoim systemie
product_namestringNazwa produktu
course_idsarray<uuid>Kursy, do których pozycja nadaje dostęp na poziomie zwykłym
coursesarrayKursy z poziomem dostępu: { "id": uuid, "access_level": 0 albo 1 }
s3_keysarrayPliki/treści cyfrowe (key, name, description, cover_key, uri, chat)

Poziom dostępu w pozycji zamówienia

Pole courses pozwala nadać dostęp od razu na poziomie Premium, dzięki czemu zakup droższego wariantu otwiera kupującemu sekcje oznaczone jako premiumowe bez żadnej ręcznej akcji.

Oba pola można wysyłać razem. Nadany zostaje wtedy zbiór obu list, a nie ich część wspólna: kurs obecny tylko w courses również dostaje dostęp. Jeśli ten sam kurs pojawi się w obu polach, decyduje poziom z courses. Brak access_level we wpisie znaczy poziom zwykły.

Samo course_ids działa dokładnie tak jak przed wprowadzeniem poziomów, więc integracja może zostać przy nim bez żadnych zmian.

curl
curl -X POST \
  -H "X-API-KEY: twoj-klucz-api" \
  -H "Content-Type: application/json" \
  -d '{
        "order": {
          "email": "jan@example.com",
          "external_id": "ZAM-2026-0001",
          "ordinal_number": "0001/2026",
          "ordered_contents": [
            { "product_id": "P-100", "product_name": "Kurs pszczelarstwa Premium",
              "courses": [{ "id": "0a1b2c3d-...", "access_level": 1 }] }
          ]
        }
      }' \
  https://twoja-subdomena.tresci.online/api/orders
Odpowiedź (utworzono)
{ "id": "9f8e7d6c-..." }

Sukces → 201 Created z id zamówienia. Zamówienie już zarejestrowane → 200. Brak wymaganych pól → 400.

DELETE /api/orders/:id

Anuluje wcześniej zarejestrowane zamówienie (np. przy zwrocie) i cofa powiązane dostępy.

curl
curl -X DELETE \
  -H "X-API-KEY: twoj-klucz-api" \
  https://twoja-subdomena.tresci.online/api/orders/9f8e7d6c-...

Sukces (także gdy zamówienie było już anulowane) → 200. Nieznane zamówienie → 404.

Użytkownicy
GET /api/users/enrollments

Zwraca listę kursów, do których przypisany jest uczestnik o podanym adresie e-mail. Uwzględnia tylko aktywne zapisy i aktywne kursy danego konta. Nieznany lub pusty e-mail zwraca pustą listę (200).

Parametry

ParametrTypWymaganeOpis
emailstring (query)TakE-mail uczestnika (porównywany bez rozróżniania wielkości liter)
curl
curl -H "X-API-KEY: twoj-klucz-api" \
  "https://twoja-subdomena.tresci.online/api/users/enrollments?email=jan@example.com"
Przykład odpowiedzi
{
  "email": "jan@example.com",
  "courses": [
    {
      "id": "0a1b2c3d-4e5f-6789-abcd-ef0123456789",
      "title": "Kurs pszczelarstwa",
      "started_at": "2026-05-01T08:30:00.000Z",
      "viewed_at": "2026-05-12T19:04:00.000Z"
    }
  ]
}
Konfiguracja platformy

API konfiguracji

Osobna część API do ustawiania platformy bez panelu: wygląd, sekcja powitalna, szablony maili platformy i kursów, dostawca wysyłki maili oraz webhooki. Obejmuje to, co admin ustawia w panelu. Zapis przechodzi przez te same walidacje co formularze panelu.

Base URL
https://{subdomena}.tresci.online/api/v1/configuration/

Ta część wymaga klucza konfiguracyjnego, a nie klucza API opisanego wyżej. Utworzysz go w panelu: Ustawienia → API → Klucze konfiguracyjne. Pełny token zobaczysz raz, zaraz po utworzeniu. Klucz możesz odwołać i ustawić mu datę wygaśnięcia. Działa wyłącznie na platformie, na której go utworzono.

Zakresy klucza

ZakresCo daje
readOdczyt całej konfiguracji. Wartości sekretów nigdy nie są zwracane.
write_appearanceZapis: platforma, sekcja powitalna, szablony maili platformy i kursów.
write_configZapis: dostawca wysyłki maili i webhooki.

Format

Zapisy (POST, PATCH, PUT) wymagają nagłówka Content-Type: application/json. Odpowiedź sukcesu ma kopertę data, listy mogą mieć też meta. PATCH zmienia tylko przesłane pola. Sekrety są tylko do zapisu: odczyt zwraca pole <nazwa>_configured, a sekret pominięty albo pusty zostaje bez zmian.

Błąd walidacji (422)
{
  "error": "Unprocessable Entity",
  "errors": { "primary_color": ["Powinien mieć format #XXXXXX"] }
}

Zapisy konfiguracji mają własny limit: 10 na minutę na klucz. Każde żądanie, także odrzucone, trafia do logu audytowego platformy.

Klucz z zakresem write_config zmienia dostawcę wysyłki i adresy webhooków. Wydawaj go tylko integracjom, które tego potrzebują. Do zmiany wyglądu wystarczą read i write_appearance.

GET /api/v1/configuration/self

Sprawdza klucz. Działa z każdym zakresem.

curl
curl -H "X-API-KEY: twoj-klucz-konfiguracyjny" \
  https://twoja-subdomena.tresci.online/api/v1/configuration/self
Przykład odpowiedzi
{
  "data": {
    "platform": { "subdomain": "akademia", "title": "Akademia" },
    "key": { "name": "Konfiguracja", "prefix": "3f9a1c2b", "scopes": ["read", "write_appearance"], "expires_at": null }
  }
}
GET PATCH /api/v1/configuration/platform

Ustawienia ze strony panelu „Admin”. Zapis wymaga, żeby platforma miała tytuł, tak jak w panelu.

Pola

PoleTypOpis
title, public_hero_title, public_hero_descriptionstringNazwa platformy i nagłówek otwartej platformy
primary_color, navbar_color, navbar_font_color, social_icons_colorstringKolor w formacie #RRGGBB
open_platform_enabled, login_frame_enabled, open_platform_about_enabled, open_platform_contact_enabledbooleanPrzełączniki otwartej platformy
open_platform_about_content, open_platform_contact_content, platform_rulesstring (HTML)Strony „O nas”, „Kontakt” i regulamin
social_facebook, social_instagram, social_youtube, social_tiktok, social_linkedinstring (URL)Profile w mediach społecznościowych
footerobject{ "content": "<p>...</p>" }
default_email_senderobject{ "name": "...", "email": "..." }
course_global_configobject{ "video_border": true }
logo, favicon, mobile_iconobjectObiekt z polami filename, content_type i data (plik w base64). PNG albo JPEG, poniżej 5 MB, typ sprawdzany z zawartości pliku. Odczyt zwraca logo_url, favicon_url, mobile_icon_url.
curl
curl -X PATCH https://twoja-subdomena.tresci.online/api/v1/configuration/platform \
  -H "X-API-KEY: twoj-klucz-konfiguracyjny" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Akademia",
    "primary_color": "#CE0037",
    "logo": { "filename": "logo.png", "content_type": "image/png", "data": "iVBORw0KGgo..." }
  }'
GET PATCH /api/v1/configuration/welcome_section

Sekcja powitalna: welcome_title, welcome_text (HTML), welcome_video_url, welcome_bg_color, welcome_title_color, welcome_text_color oraz welcome_cover w base64 jak logo. "welcome_cover": null usuwa okładkę.

GET PATCH /api/v1/configuration/email_templates[/:slug]

Szablony maili platformy, m.in. user_invitation (zaproszenie) i user_reinvitation (ponowne zaproszenie). Lista zwraca slug, name, subject, tags i customized. Pojedynczy szablon ma dodatkowo host, sender_name, sender_email i description (treść HTML).

Pierwszy PATCH tworzy kopię szablonu dla Twojej platformy (customized: true). Szablon domyślny zostaje bez zmian.

AkcjaOpis
POST /email_templates/:slug/restoreUsuwa kopię i przywraca szablon domyślny. Bez kopii zwraca 404.
POST /email_templates/:slug/send_test{ "email": "..." }, odpowiedź 202. Wysyłka testowa działa tylko na adres admina tej platformy.

Zaproszenia (user_invitation, user_reinvitation, community_access_granted) muszą zawierać {{LINK_LOGOWANIE}} jako zwykły tekst. Bez niego uczestnik nie dostanie linku do platformy, więc zapis kończy się 422. Tag wstawiony jako adres linku (<a href="{{LINK_LOGOWANIE}}">) też daje 422.

curl
curl -X PATCH https://twoja-subdomena.tresci.online/api/v1/configuration/email_templates/user_invitation \
  -H "X-API-KEY: twoj-klucz-konfiguracyjny" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Twój dostęp do Akademii",
    "description": "<p>Dzień dobry!</p><p>Wejdź na platformę: {{LINK_LOGOWANIE}}</p>"
  }'
GET PATCH POST /api/v1/configuration/courses/:course_id/email_templates[/:slug]

Szablony maili konkretnego kursu (:course_id to id albo slug kursu). Działają jak szablony platformy i mają dodatkowe pola active, send_after (liczba dni) i notify_previous_users. Obsługują też restore i send_test.

AkcjaOpis
POST /courses/:course_id/email_templatesMail wysyłany po ukończeniu lekcji: { "send_after_lesson": "<id lekcji>", "subject", "description", "active" }. Lekcja musi należeć do tego kursu. Odpowiedź 201.
PATCH /courses/:course_id/custom_invitation{ "enabled": true } włącza własne zaproszenie do kursu i tworzy szablony course_invitation oraz course_reinvitation. One też wymagają {{LINK_LOGOWANIE}}.
GET PUT /api/v1/configuration/email_delivery[/:provider]

Dostawca wysyłki maili platformy. Zapis wymaga zakresu write_config. :provider to emaillabs, amazon_ses albo messageflow. Gdy aktywnych jest kilku, maile wysyła pierwszy aktywny w kolejności: EmailLabs, Amazon SES, MessageFlow.

DostawcaPolaSekrety
emaillabsactive, smtp_account, emailapp_key, secret_key (sprawdzane w EmailLabs przy zapisie)
amazon_sesactive, region, email, display_namesmtp_username, smtp_password (zapis wysyła mail testowy do symulatora SES)
messageflowactive, smtp_account, emailapplication_key, authorization_key
Przykład odpowiedzi GET
{
  "data": {
    "active_provider": "messageflow",
    "emaillabs": { "configured": false },
    "amazon_ses": { "configured": false },
    "messageflow": {
      "configured": true, "active": true, "smtp_account": "1.konto.smtp", "email": "kontakt@twojadomena.pl",
      "application_key_configured": true, "authorization_key_configured": true
    }
  }
}

Sekretu nie da się wyczyścić. Żeby wyłączyć dostawcę, wyślij "active": false.

GET POST PATCH DELETE /api/v1/configuration/webhooks[/:id]

Webhooki platformy. Zapis wymaga zakresu write_config. Pola: name, url, events, active i secret_key (tylko do zapisu, służy do podpisu X-Webhook-Signature). Lista zwraca w meta.available_events dostępne zdarzenia: lesson_completed, course_completed, quiz_passed, user_registered, access_granted, access_revoked, order_fulfilled.

GET /webhooks/:id/deliveries?page=1 zwraca historię dostaw po 25 na stronę. Webhooki na adresy sieci wewnętrznej (prywatne, lokalne) nie są wysyłane, a dostawa dostaje status failed.

curl
curl -X POST https://twoja-subdomena.tresci.online/api/v1/configuration/webhooks \
  -H "X-API-KEY: twoj-klucz-konfiguracyjny" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM",
    "url": "https://twoj-crm.pl/webhooks/tresci",
    "events": ["user_registered", "course_completed"],
    "secret_key": "twoj-sekret-do-podpisu"
  }'
Referencja

Kody błędów

KodOpis
400Brak wymaganych parametrów lub błąd walidacji (np. nieistniejący kurs / niepoprawny e-mail)
401Brak lub nieprawidłowy klucz API, albo niedozwolona domena w nagłówku Referer
403Zablokowane IP — zbyt wiele żądań bez klucza (czasowy ban), albo w API konfiguracji klucz bez wymaganego zakresu
404Zasób nie znaleziony
415API konfiguracji: zapis bez nagłówka Content-Type: application/json
422API konfiguracji: błąd walidacji, szczegóły w polu errors
429Przekroczono limit requestów (patrz Rate Limiting) — nagłówek Retry-After
500Wewnętrzny błąd serwera

Zbuduj integrację
z platformą Treści Online

Spnij swój sklep, system płatności lub CRM z platformą kursową i nadawaj dostępy automatycznie. Potrzebujesz pomocy z wdrożeniem?

Porozmawiajmy →

Wsparcie techniczne · Pełna dokumentacja · Środowisko testowe (beta)