Połącz sklep internetowy salonu (Shopify, WooCommerce albo własny) z SilkCRM: pokaż w sklepie ofertę salonu, wydawaj vouchery i karnety sprzedane online, a o zdarzeniach w salonie dowiaduj się z webhooków.
REST API SilkCRM dla sklepów internetowych salonów: odczyt oferty salonu oraz wydawanie voucherów kwotowych i karnetów sprzedanych w sklepie.
Sprawdź plan salonu. Dostęp przez API mają plany Pro i wyższe. Inny plan dostaje 403 feature_not_available_on_plan.
Wygeneruj klucz API. W aplikacji wejdź w Ustawienia → Zaawansowane → Klucze API. W karcie „Nowy klucz” wpisz nazwę (np. „Sklep Shopify”), w „Poziom uprawnień” zostaw „Tylko odczyt”, w „Dodatkowe uprawnienia” zaznacz „Sklep internetowy (vouchery i karnety ze sklepu)” i kliknij „Utwórz klucz”. Taki klucz ma zakresy read:* i write:commerce. Pełny klucz zobaczysz tylko raz.
Trzymaj klucz po stronie serwera. Zapisz go w zmiennej środowiskowej SILK_API_KEY serwera sklepu. Nigdy nie wstawiaj go do kodu wykonywanego w przeglądarce klientki: kto zna klucz, wydaje vouchery w imieniu salonu.
Wyślij pierwsze zapytanie i sprawdź, które salony widzi klucz:
Każde zapytanie niesie klucz API salonu w nagłówku Authorization: Bearer silk_live_…. Inne sposoby logowania (np. OAuth) dostają 403 api_key_required. Odczyty wymagają zakresu read:*, zapisy - zakresu write:commerce (nie wynika z write:all). Plan salonu musi obejmować dostęp przez API (inaczej 403 feature_not_available_on_plan).
Każdy przykład pochodzi z prawdziwego przebiegu na koncie testowym. Wybór języka (curl, JavaScript, PHP dla WordPressa i WooCommerce) obowiązuje na całej stronie.
Voucher kupiony w sklepie
Klientka płaci w sklepie za voucher kwotowy. Sklep po opłaceniu zamówienia zakłada (albo odnajduje) jej kartę w Silku i wydaje voucher. Silk nic klientce nie wysyła, wiadomość z kodem zostaje po stronie sklepu.
Znajdź albo załóż kartę klientki po telefonie lub e-mailu z zamówienia. Zgody marketingowe przekazujesz tylko wtedy, gdy klientka je w sklepie zaznaczyła. POST /clients/resolve
Przy zwrocie zamówienia unieważnij voucher. Działa wyłącznie dla vouchera utworzonego przez API dla tego samego zamówienia i tylko, dopóki nie został użyty. POST /vouchers/{id}/void
Shopify i WooCommerce potrafią wysłać to samo powiadomienie o zamówieniu kilka razy. Wysyłaj każdy zapis z Idempotency-Key zbudowanym z numeru zamówienia i pozycji: ponowienie dostaje tę samą odpowiedź z nagłówkiem Idempotent-Replay: true, a drugi voucher nie powstaje.
To samo żądanie wysłane drugi raz z tym samym kluczem idempotencji:
Ponowienie z tym samym Idempotency-Key - ta sama odpowiedź, bez drugiego vouchera
Nagłówek Silk-Dry-Run: 1 wykonuje zapis w całości, łącznie z walidacją i regułami salonu, po czym go wycofuje. Tak sprawdzisz integrację na prawdziwym koncie, zanim sklep zacznie wydawać vouchery naprawdę.
Próba wydania vouchera: odpowiedź ma dry_run: true i id: null.
Próba (Silk-Dry-Run: 1) - nic nie zostaje zapisane, id = null
Reguły salonu obowiązują także w próbie: kwota poza zakresem daje ten sam 422 z nagłówkiem Silk-Dry-Run: 1 i bez niego. Poniżej ten błąd na zwykłym zapisie:
HTTP 422
{
"error": {
"code": "voucher_amount_out_of_range",
"message": "Kwota vouchera jest poza zakresem ustawionym przez salon.",
"details": {
"min_cents": 5000,
"max_cents": 50000
},
"request_id": "req-8f1c0001"
}
}
Sprawdzenie stanu zamówienia
Jedno zapytanie zwraca wszystko, co Silk utworzył dla zamówienia sklepu: vouchery i karnety z ich bieżącym stanem. Przydaje się do uzgodnień i do panelu obsługi sklepu. Znak # w numerze zamówienia koduj jako %23.
Wizyta z zadatkiem opłaconym w sklepieWkrótce - od 11 listopada 2026
Rezerwacja wizyty z zadatkiem pobranym przez sklep. Zakres i szczegóły opublikujemy razem z udostępnieniem funkcji.
Referencja
Referencja REST API v1
Wszystkie operacje z dokumentu OpenAPI, w kolejności: Katalog, Klientki, Vouchery, Karnety, Zamówienia. Adres każdej operacji to https://app.silkcrm.net/api/rest/v1 + ścieżka.
Katalog
Oferta salonu do pokazania w sklepie: salony, usługi, specjalistki, szablony karnetów.
GET/locations
Lista salonów
Zakres klucza: read:*Limit: 120 zapytań na minutęoperationId: listLocations
Salony (lokalizacje) konta, posortowane po identyfikatorze. accepts_online_bookings mówi, czy salon przyjmuje rezerwacje online; katalog usług i specjalistek odpowiada także dla salonu, który ich nie przyjmuje.
Parametry
Parametry
Parametr
Gdzie
Opis
limit
zapytanie
Liczba elementów na stronie (1-100, domyślnie 50).
cursor
zapytanie
Kursor następnej strony z pola next_cursor poprzedniej odpowiedzi. Nieprzezroczysty; zły kursor = 400 invalid_cursor.
Zakres klucza: read:*Limit: 120 zapytań na minutęoperationId: listServices
Usługi widoczne online (bez archiwalnych i ukrytych, dostępnych tylko z linku). Odpowiada także dla salonu, który nie przyjmuje rezerwacji online (patrz accepts_online_bookings w GET /locations). Ceny w groszach; price_mode mówi, które pola ceny są wypełnione.
Parametry
Parametry
Parametr
Gdzie
Opis
location_idwymagany
ścieżka
Identyfikator salonu z GET /locations. Obcy i nieistniejący salon = ten sam 404.
limit
zapytanie
Liczba elementów na stronie (1-100, domyślnie 50).
cursor
zapytanie
Kursor następnej strony z pola next_cursor poprzedniej odpowiedzi. Nieprzezroczysty; zły kursor = 400 invalid_cursor.
Zakres klucza: read:*Limit: 120 zapytań na minutęoperationId: listSpecialists
Osoby przyjmujące klientki w salonie. service_ids wskazuje wyłącznie usługi z GET /locations/{location_id}/services (widoczne online). Odpowiada także dla salonu bez rezerwacji online.
Parametry
Parametry
Parametr
Gdzie
Opis
location_idwymagany
ścieżka
Identyfikator salonu z GET /locations. Obcy i nieistniejący salon = ten sam 404.
limit
zapytanie
Liczba elementów na stronie (1-100, domyślnie 50).
cursor
zapytanie
Kursor następnej strony z pola next_cursor poprzedniej odpowiedzi. Nieprzezroczysty; zły kursor = 400 invalid_cursor.
Zakres klucza: read:*Limit: 120 zapytań na minutęoperationId: listPassTemplates
Aktywne szablony karnetów ze stałą ceną. Sklep może sprzedać wyłącznie szablon z sellable: true (salon sprzedaje go poza kasą). Szablony promocyjne („N-ty zabieg za X zł”) nie mają stałej ceny i nie pojawiają się na liście.
Parametry
Parametry
Parametr
Gdzie
Opis
limit
zapytanie
Liczba elementów na stronie (1-100, domyślnie 50).
cursor
zapytanie
Kursor następnej strony z pola next_cursor poprzedniej odpowiedzi. Nieprzezroczysty; zły kursor = 400 invalid_cursor.
Karta klientki salonu po telefonie lub e-mailu z zamówienia.
POST/clients/resolve
Znajdź albo załóż kartę klientki
Zakres klucza: write:commerceLimit: 60 zapytań na minutęoperationId: resolveClient
Dopasowuje klientkę po telefonie (dowolny zapis, np. 500 100 200, +48 500-100-200), a bez niego po e-mailu; brak dopasowania zakłada nową kartę. Odpowiedź niesie wyłącznie identyfikator karty, nigdy dane osobowe. Dane istniejącej karty nie są nadpisywane.
Zgody marketingowe ze sklepu: wyłącznie NADANIE (granted: true z chwilą udzielenia). Zgoda jest pomijana, gdy jest starsza niż ostatnie cofnięcie tego kanału przez klientkę; zgoda e-mail nie wraca nigdy po odbiciu albo skardze u dostawcy poczty.
Karta nie jest wiązana z pozycją zamówienia - jedna klientka obsługuje wiele zamówień. W dry-runie nowa karta ma client_id: null.
Wymaga zakresu write:commerce i nagłówka Idempotency-Key. Treść jest walidowana PRZED kontrolą klucza idempotencji (zła treść = 400 invalid_request także bez klucza). Silk-Dry-Run: 1 wykonuje całą operację i ją wycofuje.
Parametry
Parametry
Parametr
Gdzie
Opis
Idempotency-Keywymagany
nagłówek
Klucz idempotencji zapisu, osobny dla każdego klucza API. Ten sam klucz i ta sama treść = powtórka zapisanej odpowiedzi; ta sama wartość z inną treścią = 409 idempotency_key_reused. Brak = 400 idempotency_key_required, zły format = 400 invalid_request.
Silk-Dry-Run
nagłówek
1 = próba bez skutków (zapis wycofany), 0 albo brak = zwykły zapis. Każda inna wartość = 400 invalid_request.
Treść żądania
Treść POST /clients/resolve.
Pola żądania Znajdź albo załóż kartę klientki
Pole
Typ
Uwagi
external_order_idwymagane
string
1-100 znaków
external_order_line_id
string
do 100 znaków
shop
string
jedno z: shopify, woocommerce, other
clientwymagane
ClientInput
-
client.phone
string
1-40 znaków
client.email
string
format email · do 255 znaków
client.first_name
string
1-100 znaków
client.last_name
string
do 100 znaków
client.consents
object
-
client.consents.sms
ConsentGrant
-
client.consents.sms.grantedwymagane
boolean
zawsze true
client.consents.sms.granted_atwymagane
string
format date-time
client.consents.email
ConsentGrant
-
client.consents.email.grantedwymagane
boolean
zawsze true
client.consents.email.granted_atwymagane
string
format date-time
Odpowiedź 200 · ResolveClientResponse
Identyfikator karty klientki, bez danych osobowych.
Vouchery kwotowe sprzedane w sklepie: wydanie, odczyt, zwrot.
POST/vouchers
Wydaj voucher kwotowy
Zakres klucza: write:commerceLimit: 60 zapytań na minutęoperationId: createVoucher
Voucher kwotowy sprzedany w sklepie. Odbiorczyni to DOKŁADNIE jedno z: client_id, client (znajdź albo załóż kartę) i recipient_phone (numer bez karty - voucher czeka pod nim). Opcjonalna purchaser to osoba płacąca, gdy voucher jest prezentem.
paid_cents < amount_cents = sprzedaż z rabatem: wartość vouchera zostaje pełna, zapłata trafia do paid_cents. Kwota musi mieścić się w zakresie ustawionym przez salon (422 voucher_amount_out_of_range z details.min_cents/max_cents).
VAT i fiskalizacja: sprzedaż vouchera to wpłata na bon wielokrotnego przeznaczenia - sklep NIE wystawia za nią paragonu fiskalnego, salon fiskalizuje przy realizacji vouchera. Silk niczego nie wysyła klientce (ani SMS, ani e-mail).
Pozycja zamówienia (external_order_id + external_order_line_id + shop) realizuje się raz: drugi zapis tej pozycji innym kluczem idempotencji = 409 order_line_already_fulfilled z details.existing_id.
Wymaga zakresu write:commerce i nagłówka Idempotency-Key. Treść jest walidowana PRZED kontrolą klucza idempotencji (zła treść = 400 invalid_request także bez klucza). Silk-Dry-Run: 1 wykonuje całą operację i ją wycofuje.
Parametry
Parametry
Parametr
Gdzie
Opis
Idempotency-Keywymagany
nagłówek
Klucz idempotencji zapisu, osobny dla każdego klucza API. Ten sam klucz i ta sama treść = powtórka zapisanej odpowiedzi; ta sama wartość z inną treścią = 409 idempotency_key_reused. Brak = 400 idempotency_key_required, zły format = 400 invalid_request.
Silk-Dry-Run
nagłówek
1 = próba bez skutków (zapis wycofany), 0 albo brak = zwykły zapis. Każda inna wartość = 400 invalid_request.
Treść żądania
Treść POST /vouchers: dokładnie jedno z client_id, client, recipient_phone.
Voucher kwotowy. amount_cents = wartość, balance_cents = saldo, paid_cents = zapłata w sklepie. W dry-runie pola obiektów, które dopiero by powstały, są null.
Pola odpowiedzi Wydaj voucher kwotowy
Pole
Typ
Uwagi
idwymagane
string | null
-
statuswymagane
string
jedno z: pending_payment, active, used_up, expired, void
Zakres klucza: read:*Limit: 120 zapytań na minutęoperationId: getVoucher
Aktualny stan vouchera: saldo, status, ważność. external_order_id = numer zamówienia sklepu, z którego voucher powstał (null dla vouchera z kasy salonu).
Parametry
Parametry
Parametr
Gdzie
Opis
idwymagany
ścieżka
Identyfikator zwrócony przy wydaniu. Obcy, nieistniejący i obiekt innego rodzaju = ten sam 404.
Odpowiedź 200 · Voucher
Voucher kwotowy. amount_cents = wartość, balance_cents = saldo, paid_cents = zapłata w sklepie. W dry-runie pola obiektów, które dopiero by powstały, są null.
Pola odpowiedzi Odczytaj voucher
Pole
Typ
Uwagi
idwymagane
string | null
-
statuswymagane
string
jedno z: pending_payment, active, used_up, expired, void
Zakres klucza: write:commerceLimit: 60 zapytań na minutęoperationId: voidVoucher
Zwrot zamówienia w sklepie. Unieważnić można wyłącznie obiekt utworzony przez API dla TEGO SAMEGO zamówienia (external_order_id + shop z treści; pozycja nie musi się zgadzać). Voucher lub karnet z kasy salonu, z innego zamówienia, obcy, innego rodzaju i nieistniejący dają ten sam 404 not_found. Obiekt zrealizowany choćby w części (każda niezwrócona realizacja, także voucher wykorzystany w całości albo wygasły po realizacji) = 409 fund_partially_used; zamknięty bez niezwróconej realizacji (już unieważniony, wygasły nietknięty) = 409 fund_already_closed.
Wymaga zakresu write:commerce i nagłówka Idempotency-Key. Treść jest walidowana PRZED kontrolą klucza idempotencji (zła treść = 400 invalid_request także bez klucza). Silk-Dry-Run: 1 wykonuje całą operację i ją wycofuje.
Parametry
Parametry
Parametr
Gdzie
Opis
idwymagany
ścieżka
Identyfikator zwrócony przy wydaniu. Obcy, nieistniejący i obiekt innego rodzaju = ten sam 404.
Idempotency-Keywymagany
nagłówek
Klucz idempotencji zapisu, osobny dla każdego klucza API. Ten sam klucz i ta sama treść = powtórka zapisanej odpowiedzi; ta sama wartość z inną treścią = 409 idempotency_key_reused. Brak = 400 idempotency_key_required, zły format = 400 invalid_request.
Silk-Dry-Run
nagłówek
1 = próba bez skutków (zapis wycofany), 0 albo brak = zwykły zapis. Każda inna wartość = 400 invalid_request.
Treść żądania
Treść zwrotu: numer zamówienia, z którego powstał obiekt; reason domyślnie „Zwrot w sklepie internetowym”.
Pola żądania Unieważnij voucher (zwrot w sklepie)
Pole
Typ
Uwagi
external_order_idwymagane
string
1-100 znaków
external_order_line_id
string
do 100 znaków
shop
string
jedno z: shopify, woocommerce, other
reason
string
do 200 znaków
Odpowiedź 200 · Voucher
Voucher kwotowy. amount_cents = wartość, balance_cents = saldo, paid_cents = zapłata w sklepie. W dry-runie pola obiektów, które dopiero by powstały, są null.
Pola odpowiedzi Unieważnij voucher (zwrot w sklepie)
Pole
Typ
Uwagi
idwymagane
string | null
-
statuswymagane
string
jedno z: pending_payment, active, used_up, expired, void
Karnety sprzedane w sklepie: wydanie, odczyt, zwrot.
POST/passes
Wydaj karnet
Zakres klucza: write:commerceLimit: 60 zapytań na minutęoperationId: createPass
Karnet z szablonu, który salon sprzedaje poza kasą (sellable: true w GET /pass-templates). Karnet wymaga karty klientki: DOKŁADNIE jedno z client_id i client.
paid_cents mniejsze od ceny szablonu = sprzedaż z rabatem: liczba wejść zostaje z szablonu, wartość jednego wejścia (unit_value_cents) liczy się od zapłaty.
VAT i fiskalizacja: sprzedaż karnetu fiskalizuje sklep - Silk nie wystawia paragonu. Silk niczego nie wysyła klientce.
Pozycja zamówienia realizuje się raz: drugi zapis tej pozycji innym kluczem idempotencji = 409 order_line_already_fulfilled z details.existing_id.
Wymaga zakresu write:commerce i nagłówka Idempotency-Key. Treść jest walidowana PRZED kontrolą klucza idempotencji (zła treść = 400 invalid_request także bez klucza). Silk-Dry-Run: 1 wykonuje całą operację i ją wycofuje.
Parametry
Parametry
Parametr
Gdzie
Opis
Idempotency-Keywymagany
nagłówek
Klucz idempotencji zapisu, osobny dla każdego klucza API. Ten sam klucz i ta sama treść = powtórka zapisanej odpowiedzi; ta sama wartość z inną treścią = 409 idempotency_key_reused. Brak = 400 idempotency_key_required, zły format = 400 invalid_request.
Silk-Dry-Run
nagłówek
1 = próba bez skutków (zapis wycofany), 0 albo brak = zwykły zapis. Każda inna wartość = 400 invalid_request.
Treść żądania
Treść POST /passes: dokładnie jedno z client_id i client.
Pola żądania Wydaj karnet
Pole
Typ
Uwagi
external_order_idwymagane
string
1-100 znaków
external_order_line_id
string
do 100 znaków
shop
string
jedno z: shopify, woocommerce, other
template_idwymagane
string
1-100 znaków
paid_centswymagane
integer
≥ 0
client_id
string
1-100 znaków
client
ClientInput
-
client.phone
string
1-40 znaków
client.email
string
format email · do 255 znaków
client.first_name
string
1-100 znaków
client.last_name
string
do 100 znaków
client.consents
object
-
client.consents.sms
ConsentGrant
-
client.consents.sms.grantedwymagane
boolean
zawsze true
client.consents.sms.granted_atwymagane
string
format date-time
client.consents.email
ConsentGrant
-
client.consents.email.grantedwymagane
boolean
zawsze true
client.consents.email.granted_atwymagane
string
format date-time
Odpowiedź 201 · Pass
Karnet. uses_left = pozostałe wejścia, unit_value_cents = wartość jednego wejścia. W dry-runie pola obiektów, które dopiero by powstały, są null.
Pola odpowiedzi Wydaj karnet
Pole
Typ
Uwagi
idwymagane
string | null
-
statuswymagane
string
jedno z: pending_payment, active, used_up, expired, void
Zakres klucza: read:*Limit: 120 zapytań na minutęoperationId: getPass
Aktualny stan karnetu: pozostałe wejścia, status, ważność. external_order_id = numer zamówienia sklepu, z którego karnet powstał (null dla karnetu z kasy salonu).
Parametry
Parametry
Parametr
Gdzie
Opis
idwymagany
ścieżka
Identyfikator zwrócony przy wydaniu. Obcy, nieistniejący i obiekt innego rodzaju = ten sam 404.
Odpowiedź 200 · Pass
Karnet. uses_left = pozostałe wejścia, unit_value_cents = wartość jednego wejścia. W dry-runie pola obiektów, które dopiero by powstały, są null.
Pola odpowiedzi Odczytaj karnet
Pole
Typ
Uwagi
idwymagane
string | null
-
statuswymagane
string
jedno z: pending_payment, active, used_up, expired, void
Zakres klucza: write:commerceLimit: 60 zapytań na minutęoperationId: voidPass
Zwrot zamówienia w sklepie. Unieważnić można wyłącznie obiekt utworzony przez API dla TEGO SAMEGO zamówienia (external_order_id + shop z treści; pozycja nie musi się zgadzać). Voucher lub karnet z kasy salonu, z innego zamówienia, obcy, innego rodzaju i nieistniejący dają ten sam 404 not_found. Obiekt zrealizowany choćby w części (każda niezwrócona realizacja, także voucher wykorzystany w całości albo wygasły po realizacji) = 409 fund_partially_used; zamknięty bez niezwróconej realizacji (już unieważniony, wygasły nietknięty) = 409 fund_already_closed.
Wymaga zakresu write:commerce i nagłówka Idempotency-Key. Treść jest walidowana PRZED kontrolą klucza idempotencji (zła treść = 400 invalid_request także bez klucza). Silk-Dry-Run: 1 wykonuje całą operację i ją wycofuje.
Parametry
Parametry
Parametr
Gdzie
Opis
idwymagany
ścieżka
Identyfikator zwrócony przy wydaniu. Obcy, nieistniejący i obiekt innego rodzaju = ten sam 404.
Idempotency-Keywymagany
nagłówek
Klucz idempotencji zapisu, osobny dla każdego klucza API. Ten sam klucz i ta sama treść = powtórka zapisanej odpowiedzi; ta sama wartość z inną treścią = 409 idempotency_key_reused. Brak = 400 idempotency_key_required, zły format = 400 invalid_request.
Silk-Dry-Run
nagłówek
1 = próba bez skutków (zapis wycofany), 0 albo brak = zwykły zapis. Każda inna wartość = 400 invalid_request.
Treść żądania
Treść zwrotu: numer zamówienia, z którego powstał obiekt; reason domyślnie „Zwrot w sklepie internetowym”.
Pola żądania Unieważnij karnet (zwrot w sklepie)
Pole
Typ
Uwagi
external_order_idwymagane
string
1-100 znaków
external_order_line_id
string
do 100 znaków
shop
string
jedno z: shopify, woocommerce, other
reason
string
do 200 znaków
Odpowiedź 200 · Pass
Karnet. uses_left = pozostałe wejścia, unit_value_cents = wartość jednego wejścia. W dry-runie pola obiektów, które dopiero by powstały, są null.
Pola odpowiedzi Unieważnij karnet (zwrot w sklepie)
Pole
Typ
Uwagi
idwymagane
string | null
-
statuswymagane
string
jedno z: pending_payment, active, used_up, expired, void
Zakres klucza: read:*Limit: 120 zapytań na minutęoperationId: getOrder
Vouchery i karnety utworzone przez API dla numeru zamówienia, w aktualnym stanie (po zwrocie status void). Numer zamówienia jest przycinany ze spacji; # koduj jako %23. Brak czegokolwiek dla tego numeru = 404 not_found.
Parametry
Parametry
Parametr
Gdzie
Opis
external_order_idwymagany
ścieżka
Numer zamówienia sklepu, przycinany ze spacji, wielkość liter ma znaczenie. Znak # koduj jako %23 (np. /orders/%231043) - surowy # zaczyna fragment adresu i nie dociera do serwera.
shop
zapytanie
Zawęża do zamówień jednego sklepu. Bez parametru: wszystkie sklepy, a przy kilku shop w odpowiedzi = null.
Odpowiedź 200 · Order
Vouchery i karnety utworzone przez API dla zamówienia sklepu.
Pola odpowiedzi Stan zamówienia sklepu w Silku
Pole
Typ
Uwagi
external_order_idwymagane
string
-
shopwymagane
object
-
voucherswymagane
array<Voucher>
-
vouchers[].idwymagane
string | null
-
vouchers[].statuswymagane
string
jedno z: pending_payment, active, used_up, expired, void
vouchers[].amount_centswymagane
integer
≥ 0
vouchers[].balance_centswymagane
integer
≥ 0
vouchers[].paid_centswymagane
integer
≥ 0
vouchers[].client_idwymagane
string | null
-
vouchers[].recipient_phonewymagane
string | null
-
vouchers[].purchaser_client_idwymagane
string | null
-
vouchers[].gift_messagewymagane
string | null
-
vouchers[].expires_atwymagane
string | null
-
vouchers[].external_order_idwymagane
string | null
-
vouchers[].created_atwymagane
string | null
-
vouchers[].dry_run
boolean
-
passeswymagane
array<Pass>
-
passes[].idwymagane
string | null
-
passes[].statuswymagane
string
jedno z: pending_payment, active, used_up, expired, void
Każdy błąd ma ten sam kształt: { "error": { "code", "message", "details"?, "request_id" } }. Rozgałęziaj się po code (lista w schemacie Error, pole x-error-codes), nie po treści message (po polsku, może się zmienić). request_id podaj przy zgłoszeniu. Obcy i nieistniejący zasób to ten sam 404 not_found.
Przykład błędu 422JSON
{
"error": {
"code": "voucher_amount_out_of_range",
"message": "Kwota vouchera jest poza zakresem ustawionym przez salon.",
"details": { "min_cents": 5000, "max_cents": 50000 },
"request_id": "req-8f1c0001"
}
}
Kody błędów REST API v1
Kod
HTTP
Znaczenie
unauthorized
401
Brak ważnego klucza API. Podaj go w nagłówku Authorization: Bearer silk_live_….
api_key_required
403
To API przyjmuje wyłącznie klucz API salonu (silk_live_…), nie inne sposoby logowania.
insufficient_scope
403
Klucz API nie ma uprawnienia do tej operacji. Zapisy wymagają zakresu write:commerce.
feature_not_available_on_plan
403
Plan salonu nie obejmuje dostępu przez API.
tenant_suspended
403
Konto salonu jest zawieszone. Skontaktuj się z obsługą SilkCRM.
rate_limited
429
Przekroczono limit zapytań. Spróbuj ponownie za chwilę.
invalid_request
400
Zapytanie ma niepoprawne parametry albo treść.
invalid_cursor
400
Kursor stronicowania jest nieprawidłowy. Pobierz listę od początku.
not_found
404
Nie znaleziono zasobu.
idempotency_key_required
400
Zapis wymaga nagłówka Idempotency-Key.
idempotency_key_reused
409
Ten Idempotency-Key był już użyty z inną treścią zapytania.
order_line_already_fulfilled
409
Ta pozycja zamówienia została już zrealizowana.
client_not_found
422
Nie znaleziono klientki salonu.
client_identity_required
422
Podaj numer telefonu albo adres e-mail klientki.
client_limit_reached
422
Salon osiągnął limit klientek w swoim planie.
vouchers_disabled
422
Salon nie sprzedaje voucherów.
voucher_amount_out_of_range
422
Kwota vouchera jest poza zakresem ustawionym przez salon.
passes_disabled
422
Salon nie sprzedaje karnetów.
pass_template_not_sellable
422
Tego karnetu nie można sprzedać.
pass_template_promotional
422
Karnetu promocyjnego nie można sprzedać przez API.
payment_exceeds_value
422
Kwota zapłaty przekracza wartość vouchera lub karnetu.
fund_partially_used
409
Voucher lub karnet został już częściowo wykorzystany.
fund_already_closed
409
Voucher lub karnet jest już zamknięty.
internal_error
500
Wystąpił błąd po stronie Silk. Spróbuj ponownie; jeśli się powtarza, podaj request_id.
Limity
Limity zapytań
Limity liczą się osobno dla każdej trasy i każdego klucza API: odczyty 120 zapytań na minutę, zapisy 60 zapytań na minutę (osobne liczniki). Po przekroczeniu: 429 rate_limited z details.retry_after (sekundy) i nagłówkiem Retry-After.
Limity zapytań
Rodzaj
Limit
Licznik
Odczyt (GET)
120 zapytań na minutę
osobno dla każdej trasy i każdego klucza API
Zapis (POST)
60 zapytań na minutę
osobny licznik zapisów, dla każdej trasy i każdego klucza API
Idempotencja
Ponawianie zapisów bez duplikatów
Każdy zapis wymaga nagłówka Idempotency-Key (1-255 znaków A-Z a-z 0-9 _ - : .). Ponowienie z tym samym kluczem i tą samą treścią zwraca zapisaną odpowiedź z nagłówkiem Idempotent-Replay: true - bez drugiego skutku.
Klucze są osobne dla każdego klucza API: nowy klucz API to nowa przestrzeń kluczy idempotencji.
Porównywane są metoda, ścieżka i treść (bez query string). Ten sam klucz z inną treścią = 409 idempotency_key_reused. Ścieżka jest porównywana dosłownie, więc ten sam klucz z inaczej zapisaną ścieżką (ukośnik na końcu, inne kodowanie identyfikatora) też daje 409 idempotency_key_reused.
Zapamiętywane są wyłącznie odpowiedzi 2xx. Po błędzie ten sam klucz można ponowić z poprawioną treścią.
Równoległe żądanie z tym samym kluczem czeka na pierwsze i dostaje jego odpowiedź jako powtórkę.
Treść jest walidowana przed kontrolą klucza: zła treść daje 400 invalid_request nawet bez nagłówka.
Niezależnie od klucza pozycja zamówienia (external_order_id + external_order_line_id + shop) realizuje się raz: 409 order_line_already_fulfilled z details.existing_id.
Dobry klucz idempotencji to numer zamówienia i pozycji, np. order-1043-voucher. Przykład powtórki: ponowione powiadomienie sklepu.
Dry-run
Próba bez skutków
Nagłówek Silk-Dry-Run: 1 wykonuje zapis w całości i go wycofuje: odpowiedź ma "dry_run": true, nagłówek Silk-Dry-Run: 1, a obiekty, które dopiero by powstały, mają id: null. Brak nagłówka albo 0 = zwykły zapis; każda inna wartość = 400 invalid_request. Dry-run z kluczem idempotencji już użytym w prawdziwym zapisie zwraca zapisaną PRAWDZIWĄ odpowiedź (z "dry_run": false) oraz Silk-Dry-Run: 1.
Wartości nagłówka Silk-Dry-Run
Nagłówek Silk-Dry-Run
Skutek
1
Próba: zapis wykonany i wycofany, odpowiedź z dry_run: true i nagłówkiem Silk-Dry-Run: 1
0 albo brak
Zwykły zapis
każda inna wartość
400 invalid_request
Konwencje
Konwencje i zamówienia sklepu
Kwoty w groszach (*_cents, liczby całkowite). Czasy w ISO 8601. Identyfikatory to nieprzezroczyste napisy (UUID). Listy są stronicowane kursorem (limit, cursor → next_cursor, null = ostatnia strona).
Zamówienia sklepu
Każdy zapis podaje external_order_id (1-100 znaków, przycinany ze spacji), opcjonalnie external_order_line_id i shop (shopify, woocommerce, other - domyślnie other). W ścieżce (GET /orders/{external_order_id}) znak # koduj jako %23. Unieważnić (zwrot) można wyłącznie obiekt utworzony przez API dla tego samego zamówienia (external_order_id + shop) - każdy inny przypadek to 404.
Dane osobowe
Klientki i zgody
Odpowiedzi nie niosą danych osobowych - wyłącznie identyfikatory kart (wyjątek: recipient_phone, który podał sam sklep). Zgody marketingowe ze sklepu to wyłącznie nadanie; zgoda starsza niż ostatnie cofnięcie kanału jest pomijana, a zgoda e-mail nie wraca nigdy po odbiciu albo skardze u dostawcy poczty. Silk niczego nie wysyła klientce przy wydaniu vouchera ani karnetu.
Fiskalizacja
VAT i fiskalizacja
Voucher kwotowy: sprzedaż to wpłata na bon wielokrotnego przeznaczenia - sklep NIE wystawia paragonu fiskalnego, salon fiskalizuje przy realizacji. Karnet: sprzedaż fiskalizuje sklep; Silk nie wystawia paragonu przy sprzedaży ze sklepu.
Kto wystawia paragon
Produkt
Sprzedaż w sklepie
Kiedy powstaje paragon
Voucher kwotowy
Sklep NIE wystawia paragonu fiskalnego: sprzedaż vouchera to wpłata na bon wielokrotnego przeznaczenia.
Przy realizacji vouchera w salonie. Paragon wystawia salon.
Karnet
Sprzedaż fiskalizuje sklep. Silk nie wystawia paragonu przy sprzedaży karnetu ze sklepu.
Przy sprzedaży, w sklepie.
To opis tego, jak działa Silk. Rozliczenie podatkowe konkretnego salonu potwierdź z jego księgową.
Webhooki
Webhooki wychodzące
Webhooki powiadamiają Twój system o zdarzeniach w salonie: nowej wizycie, płatności, opinii. To osobny mechanizm od REST API v1: konfiguruje go salon w aplikacji (plany Pro i wyższe), a dostawa nie zależy od klucza API.
Konfiguracja
Ustawienia → Zaawansowane → Webhooki → „Nowy webhook”. Wypełnij „URL endpointu” (publiczny adres Twojego serwera), „Sekret HMAC” (8-500 znaków, wymagany przy tworzeniu), opcjonalny „Opis”, zaznacz „Zdarzenia” i kliknij „Dodaj webhook”. Przycisk „Test” wysyła zdarzenie próbne z polem test: true w data, a tabela „Log dostaw” pokazuje każdą próbę ze statusem i odpowiedzią Twojego serwera.
Ten sam przy każdej próbie tej samej dostawy. Użyj go do odrzucania duplikatów.
X-BeautyCRM-Event
np. appointment.created
Typ zdarzenia.
X-BeautyCRM-Signature
sha256=<hex>
HMAC SHA-256 z sekretem endpointu, liczony z timestamp.delivery.treść.
X-BeautyCRM-Timestamp
np. 2026-11-06T09:15:00.000Z
Chwila wysłania tej próby (ISO 8601). Nowa przy każdym ponowieniu.
Weryfikacja podpisu
Podpis to HMAC SHA-256 z sekretem endpointu, liczony z napisu {X-BeautyCRM-Timestamp}.{X-BeautyCRM-Delivery}.{surowa treść}, zapisany szesnastkowo z prefiksem sha256=. Licz go z bajtów, które przyszły, zanim sparsujesz JSON: ponowna serializacja zmienia treść i podpis się nie zgodzi. Porównuj w stałym czasie i odrzucaj dostawy ze znacznikiem czasu starszym niż kilka minut.
Weryfikacja podpisu webhooka
import crypto from "node:crypto";
import express from "express";
const app = express();
const MAX_AGE_MS = 5 * 60 * 1000;
const SECRET = process.env.SILK_WEBHOOK_SECRET;
if (!SECRET) throw new Error("Brak SILK_WEBHOOK_SECRET - ustaw sekret HMAC webhooka.");
// Podpis liczymy z SUROWEJ treści, więc parser JSON-a dopiero po weryfikacji.
app.post("/webhooks/silkcrm", express.raw({ type: "application/json" }), (req, res) => {
const rawBody = req.body.toString("utf8");
const timestamp = req.get("X-BeautyCRM-Timestamp") ?? "";
const deliveryId = req.get("X-BeautyCRM-Delivery") ?? "";
const signature = req.get("X-BeautyCRM-Signature") ?? "";
// Zły format nagłówka = 401 od razu (inaczej bufory różnej długości wywróciłyby timingSafeEqual).
if (!/^sha256=[0-9a-f]{64}$/.test(signature)) return res.status(401).end();
const expected = crypto
.createHmac("sha256", SECRET)
.update(`${timestamp}.${deliveryId}.${rawBody}`)
.digest();
const received = Buffer.from(signature.slice("sha256=".length), "hex");
const valid = crypto.timingSafeEqual(expected, received);
const age = Math.abs(Date.now() - Date.parse(timestamp));
if (!valid || !(age < MAX_AGE_MS)) return res.status(401).end();
const event = JSON.parse(rawBody);
// Odrzuć duplikat po deliveryId, potem obsłuż event.type i event.data.
res.status(200).end();
});
Dostawa i ponowienia
Sukces to dowolna odpowiedź 2xx w ciągu 10 sekund. Odpowiadaj od razu, a zdarzenie przetwarzaj w tle. Przekierowania (do 5) są śledzone, ale każdy adres musi być publiczny.
Silk próbuje dostarczyć zdarzenie 3 razy: od razu, po około minucie i po około 5 minutach. Zadanie ponowień chodzi co 5 minut, więc odstęp bywa dłuższy.
Ponowienie ma ten sam X-BeautyCRM-Delivery i nowy X-BeautyCRM-Timestamp. Odrzucaj duplikaty po identyfikatorze dostawy, a nie po treści. Kolejność dostaw nie jest gwarantowana.
Po trzeciej nieudanej próbie dostawa zostaje oznaczona jako nieudana, endpoint jest wyłączany, a salon dostaje powiadomienie „Webhook został dezaktywowany”. Po naprawie włącz go przełącznikiem „Endpoint aktywny”. Nieudane dostawy nie są wysyłane ponownie.
CLI
Dane salonu w terminalu
Pakiet @silkcrm/cli (polecenie silk) daje dostęp do narzędzi AI salonu z terminala: przychody, KPI, wizyty, rozliczenia. Używa tego samego klucza API, ale woła narzędzia AI (/api/v1/ai/tools), a nie REST API v1. Wymaga Node.js 20.19.6 lub nowszego.
Instalacja i kluczTerminal
npx @silkcrm/cli --help
# albo globalnie:
npm i -g @silkcrm/cli
export SILK_API_KEY=silk_live_... # klucz z Ustawień
export SILK_API_URL=https://app.silkcrm.net # opcjonalnie
Skróty (revenue, kpi, appointments, billing) tylko odczytują dane.
silk tools call wykonuje dowolne narzędzie, na które pozwala zakres klucza. Narzędzia zmieniające dane pytają o potwierdzenie (albo przyjmują --yes).
Dane klientek wracają jako tokeny zamiast imion i telefonów.
MCP
Salon w asystencie AI (MCP)
Serwer MCP daje asystentom AI (Claude, ChatGPT i innym klientom MCP) te same narzędzia salonu co CLI. Autoryzacja, izolacja salonów, kontrola ról i anonimizacja danych klientek zostają po stronie SilkCRM.
Zdalny serwer (HTTP)
Adres: https://app.silkcrm.net/mcp. Serwer przyjmuje logowanie OAuth kontem SilkCRM (tak łączy się konektor dodany w claude.ai) albo klucz API w nagłówku Authorization: Bearer silk_live_…. W claude.ai dodaj własny konektor z tym adresem i zaloguj się kontem salonu. Podłączonych asystentów zobaczysz w aplikacji: Ustawienia → Zaawansowane → Integracje → „Połączenia AI”, gdzie zmienisz ich zakres albo je odłączysz.
Lokalny serwer (stdio)
Pakiet @silkcrm/mcp uruchamia serwer na Twoim komputerze (Node.js 18 lub nowszy) z kluczem API w zmiennej SILK_API_KEY. Claude Desktop: Ustawienia → Developer → Edit Config.
# lokalnie (stdio), klucz API ze zmiennej środowiskowej
claude mcp add silkcrm -e SILK_API_KEY=$SILK_API_KEY -- npx -y @silkcrm/mcp
# zdalnie (HTTP), ten sam klucz API w nagłówku
claude mcp add --transport http silkcrm https://app.silkcrm.net/mcp \
--header "Authorization: Bearer $SILK_API_KEY"
Wersja stoi w ścieżce: /api/rest/v1. Zmiany zgodne wstecz (nowa operacja, nowe pole w odpowiedzi, nowy parametr opcjonalny) wchodzą bez zmiany wersji, więc Twój kod powinien ignorować pola, których nie zna. Zmiana niezgodna wstecz oznacza nową wersję w ścieżce.
1.0.0 2026-11-06
Pierwsze wydanie REST API v1 dla sklepów internetowych salonów.
Karta klientki po telefonie lub e-mailu z zamówienia, ze zgodami marketingowymi (tylko nadanie).
Vouchery kwotowe i karnety: wydanie, odczyt, unieważnienie przy zwrocie w sklepie.
Stan zamówienia sklepu w Silku.
Idempotencja zapisów, tryb próby Silk-Dry-Run, jednolity kształt błędów.
Pytania o integrację: tech@silkcrm.net. Do zgłoszenia dołącz request_id z odpowiedzi i prefiks klucza, nigdy cały klucz.
Używamy cookies
Niezbędne pliki cookie pozwalają nam utrzymać Twoją sesję. Statystyczne i marketingowe pomagają nam ulepszać produkt i mierzyć skuteczność kampanii. Możesz zarządzać preferencjami w każdej chwili.