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.
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.
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.
{
"courses": [
{ "id": "0a1b2c3d-...", "title": "Kurs pszczelarstwa" }
]
}
{
"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ła | Limit | Liczone wg |
|---|---|---|
| Ogólny | 100 / min | klucz API |
| Na IP | 120 / min | adres IP |
| Mutacje (POST/DELETE) | 30 / min | klucz API |
| Żądania bez klucza | 5 / 5 min | adres 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.
Lista wszystkich aktywnych kursów na koncie.
{
"courses": [
{ "id": "0a1b2c3d-4e5f-6789-abcd-ef0123456789", "title": "Kurs pszczelarstwa" },
{ "id": "11112222-3333-4444-5555-666677778888", "title": "Miód krok po kroku" }
]
}
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
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
course_id | uuid | Tak | ID kursu (z GET /api/courses) |
email | string | Tak | E-mail uczestnika |
name | string | Nie | Imię i nazwisko uczestnika |
access_level | integer | Nie | Poziom 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 -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.
Odbiera uczestnikowi dostęp do kursu.
Parametry
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
course_id | uuid | Tak | ID kursu |
email | string | Tak | E-mail uczestnika |
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.
Lista wszystkich aktywnych audiobooków na koncie.
{
"audiobooks": [
{ "id": "aaaa1111-...", "title": "Pszczoły. Audiobook" }
]
}
Nadaje uczestnikowi dostęp do audiobooka.
Parametry
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
audiobook_id | uuid | Tak | ID audiobooka (z GET /api/audiobooks) |
email | string | Tak | E-mail uczestnika |
name | string | Nie | Imię i nazwisko uczestnika |
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.
Odbiera uczestnikowi dostęp do audiobooka.
Parametry
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
audiobook_id | uuid | Tak | ID audiobooka |
email | string | Tak | E-mail uczestnika |
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.
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)
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
email | string | Tak | E-mail kupującego |
external_id | string | Tak | ID zamówienia w Twoim systemie (klucz idempotencji) |
ordinal_number | string | Nie | Numer zamówienia (do wyświetlenia) |
gift_code | string | Nie | Kod podarunkowy |
ordered_contents | array | Tak | Pozycje zamówienia — patrz niżej |
Pozycja w ordered_contents
| Pole | Typ | Opis |
|---|---|---|
product_id | string | ID produktu w Twoim systemie |
product_name | string | Nazwa produktu |
course_ids | array<uuid> | Kursy, do których pozycja nadaje dostęp na poziomie zwykłym |
courses | array | Kursy z poziomem dostępu: { "id": uuid, "access_level": 0 albo 1 } |
s3_keys | array | Pliki/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 -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
{ "id": "9f8e7d6c-..." }
Sukces → 201 Created z id zamówienia. Zamówienie już zarejestrowane → 200. Brak wymaganych pól → 400.
Anuluje wcześniej zarejestrowane zamówienie (np. przy zwrocie) i cofa powiązane dostępy.
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.
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
| Parametr | Typ | Wymagane | Opis |
|---|---|---|---|
email | string (query) | Tak | E-mail uczestnika (porównywany bez rozróżniania wielkości liter) |
curl -H "X-API-KEY: twoj-klucz-api" \
"https://twoja-subdomena.tresci.online/api/users/enrollments?email=jan@example.com"
{
"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"
}
]
}
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.
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
| Zakres | Co daje |
|---|---|
read | Odczyt całej konfiguracji. Wartości sekretów nigdy nie są zwracane. |
write_appearance | Zapis: platforma, sekcja powitalna, szablony maili platformy i kursów. |
write_config | Zapis: 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.
{
"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.
Sprawdza klucz. Działa z każdym zakresem.
curl -H "X-API-KEY: twoj-klucz-konfiguracyjny" \
https://twoja-subdomena.tresci.online/api/v1/configuration/self
{
"data": {
"platform": { "subdomain": "akademia", "title": "Akademia" },
"key": { "name": "Konfiguracja", "prefix": "3f9a1c2b", "scopes": ["read", "write_appearance"], "expires_at": null }
}
}
Ustawienia ze strony panelu „Admin”. Zapis wymaga, żeby platforma miała tytuł, tak jak w panelu.
Pola
| Pole | Typ | Opis |
|---|---|---|
title, public_hero_title, public_hero_description | string | Nazwa platformy i nagłówek otwartej platformy |
primary_color, navbar_color, navbar_font_color, social_icons_color | string | Kolor w formacie #RRGGBB |
open_platform_enabled, login_frame_enabled, open_platform_about_enabled, open_platform_contact_enabled | boolean | Przełączniki otwartej platformy |
open_platform_about_content, open_platform_contact_content, platform_rules | string (HTML) | Strony „O nas”, „Kontakt” i regulamin |
social_facebook, social_instagram, social_youtube, social_tiktok, social_linkedin | string (URL) | Profile w mediach społecznościowych |
footer | object | { "content": "<p>...</p>" } |
default_email_sender | object | { "name": "...", "email": "..." } |
course_global_config | object | { "video_border": true } |
logo, favicon, mobile_icon | object | Obiekt 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 -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..." }
}'
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ę.
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.
| Akcja | Opis |
|---|---|
POST /email_templates/:slug/restore | Usuwa 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 -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>"
}'
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.
| Akcja | Opis |
|---|---|
POST /courses/:course_id/email_templates | Mail 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}}. |
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.
| Dostawca | Pola | Sekrety |
|---|---|---|
emaillabs | active, smtp_account, email | app_key, secret_key (sprawdzane w EmailLabs przy zapisie) |
amazon_ses | active, region, email, display_name | smtp_username, smtp_password (zapis wysyła mail testowy do symulatora SES) |
messageflow | active, smtp_account, email | application_key, authorization_key |
{
"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.
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 -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"
}'
Kody błędów
| Kod | Opis |
|---|---|
400 | Brak wymaganych parametrów lub błąd walidacji (np. nieistniejący kurs / niepoprawny e-mail) |
401 | Brak lub nieprawidłowy klucz API, albo niedozwolona domena w nagłówku Referer |
403 | Zablokowane IP — zbyt wiele żądań bez klucza (czasowy ban), albo w API konfiguracji klucz bez wymaganego zakresu |
404 | Zasób nie znaleziony |
415 | API konfiguracji: zapis bez nagłówka Content-Type: application/json |
422 | API konfiguracji: błąd walidacji, szczegóły w polu errors |
429 | Przekroczono limit requestów (patrz Rate Limiting) — nagłówek Retry-After |
500 | Wewnę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)
