Przewodnik - 15 min

Połącz się z Data API

Data API udostępnia Business Entities jako wersjonowane endpointy REST pod adresem /api/data/v{version}/{route}, na przykład /api/data/v1/customers. Administrator decyduje, które encje są wystawione, jakimi polami posługuje się każda wersja i które role mogą pobierać listy, odczytywać, tworzyć, aktualizować lub usuwać. Endpoint może też wywoływać Script Module: przyjmuje parametry i odpowiada tym, co moduł zwraca. Ten przewodnik jest dla osoby, która pisze integrację: jak się połączyć, jako usługa z kluczem API albo jako użytkownik, który się loguje, i jak wywoływać endpointy.

Zanim zaczniesz

Poproś administratora przestrzeni roboczej o cztery rzeczy:

  1. Adres API. To ten sam host, z którym komunikuje się sama aplikacja. Na ekranie API Endpoints panel Try pokazuje go w swojej linii curl.
  2. Endpoint i wersję, np. customers w wersji 1. Odpowiada tylko wersja o statusie Active lub Deprecated, wersja Draft nie.
  3. Rolę z dostępem do tego endpointu dla operacji, których potrzebujesz, ustawioną w siatce Who can call it endpointu. Role admin i owner zawsze mogą wywołać wszystko.
  4. Sposób dostępu z tą rolą: klucz API dla usługi albo konto użytkownika dla osoby lub prostego skryptu.

Do wszystkiego, co działa bez nadzoru, na przykład nocnej synchronizacji, sklepu internetowego czy narzędzia do raportowania, użyj klucza API. Nie wymaga hasła, logowania ani odświeżania, a otwiera dostęp do Data API i do niczego więcej.

Połącz usługę za pomocą klucza API

Administrator tworzy API client na ekranie API Clients: podaje nazwę, role, które klient otrzyma, i opcjonalnie datę wygaśnięcia. Klientowi nie można nadać ról admin ani owner, więc ma dostęp tylko do tego, co na poszczególnych endpointach przyznano jego rolom. Klucz jest pokazywany dokładnie raz, przy tworzeniu klienta. Zapisywany jest tylko jego odcisk, więc nikt nie może go później podejrzeć, nawet administrator.

Wysyłaj klucz jako token bearer przy każdym wywołaniu:

API=https://api.example.com
KEY=ask_api_acme.q7Vt0r2Lk_dP9sXw3eNfH1mA6yZc4uBgJ8oTiR5vWnE

curl "$API/api/data/v1/customers" -H "Authorization: Bearer $KEY"
  • Klucz działa tylko pod /api/data. W każdym innym miejscu produktu jest odrzucany, więc klucz, który wyciekł, nie da dostępu do innych danych aplikacji ani do jej ustawień.
  • Jest ważny do chwili, gdy wygaśnie, klient zostanie wyłączony lub usunięty albo administrator wykona jego rotację, czyli wymieni go na nowy. Każda z tych zmian obowiązuje od następnego wywołania, które zwraca wtedy 401.
  • Zmiany wprowadzane przez usługę mają jako autora nazwę klienta, a Business Events widzą go jako użytkownika.
  • Klucz wskazuje swoją przestrzeń roboczą (ask_api_{workspace}.{secret}), więc nie trzeba jej wybierać. Trzymaj go w magazynie sekretów, nigdy w kodzie.

Przejdź dalej do sekcji Wywołaj endpoint.

Połącz się jako użytkownik: zaloguj się

Użyj dedykowanego konta, a nie konta konkretnej osoby. Token uzyskany przy logowaniu pozwala na wszystko, co ten użytkownik może zrobić w aplikacji, nie tylko na wywoływanie Data API, więc daj kontu przyznaną rolę i nic więcej, a jego hasło trzymaj w magazynie sekretów. Dla usługi lepszym wyborem jest klucz API.

Wyślij e-mail i hasło konta metodą POST na /api/v1/auth/login:

API=https://api.example.com

curl -X POST "$API/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email": "webshop-sync@example.com", "password": "..."}'

Odpowiedź zawiera tokeny:

{
  "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6...",
  "refreshToken": "q8Zr0dW3...",
  "idToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6...",
  "expiresIn": 900,
  "redirectHost": null
}
  • token to token dostępu. Wysyłaj go przy każdym wywołaniu. Wygasa po expiresIn sekundach, domyślnie po 15 minutach.
  • refreshToken pozwala uzyskać nową parę tokenów bez hasła (zobacz Utrzymuj sesję użytkownika). Domyślnie jest ważny 30 dni i działa dokładnie raz.
  • idToken i redirectHost są dla aplikacji w przeglądarce, zignoruj je.

Odrzucone logowanie zwraca 401 z polem code: invalid_credentials, disabled (konto jest wyłączone) lub no_tenant (konto nie należy do żadnej aktywnej przestrzeni roboczej). Zbyt wiele nieudanych prób kończy się odpowiedzią 429 z locked_out. Logowanie jest też ograniczone do 20 prób na minutę z jednego adresu IP, więc zaloguj się raz i utrzymuj sesję, zamiast logować się przy każdym wywołaniu.

Wywołaj endpoint

Umieść klucz API lub token dostępu w nagłówku Authorization. Poniżej $TOKEN oznacza jedno lub drugie. Wywołanie listy zwraca jedną stronę elementów oraz ich łączną liczbę:

curl "$API/api/data/v1/customers?pageSize=2&sort=name" \
  -H "Authorization: Bearer $TOKEN"
{
  "items": [
    { "id": 1, "name": "Acme", "email": "info@acme.test", "creditLimit": 500 },
    { "id": 2, "name": "Globex", "email": "hello@globex.test", "creditLimit": 50 }
  ],
  "page": 1,
  "pageSize": 2,
  "totalCount": 3
}

Nazwy pól to te, które administrator nadał tej wersji, i nie muszą odpowiadać kolumnom w bazie danych. Odczyt pojedynczego elementu, tworzenie, zmiana i usuwanie wyglądają tak:

# One item
curl "$API/api/data/v1/customers/1" -H "Authorization: Bearer $TOKEN"

# Create: answers 201 with the stored item and a Location header
curl -X POST "$API/api/data/v1/customers" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Hooli", "email": "hi@hooli.test"}'

# Change some fields
curl -X PATCH "$API/api/data/v1/customers/4" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email": "sales@hooli.test"}'

# Delete: answers 204
curl -X DELETE "$API/api/data/v1/customers/4" -H "Authorization: Bearer $TOKEN"
  • PATCH zmienia tylko pola podane w ciele żądania. PUT robi to samo, ale odrzuca ciało, w którym brakuje wymaganego pola.
  • Id zawsze pochodzi z URL-a. Pole id w ciele żądania tworzenia jest ignorowane, więc utworzenie nigdy nie nadpisze istniejącego elementu.
  • Pola tylko do odczytu w ciele żądania są ignorowane, więc możesz odesłać element dokładnie w takiej postaci, w jakiej go pobrałeś. Pole, którego wersja nie zna, jest odrzucane z kodem 400, co wyłapuje literówki.
  • Zapisy przez API działają dokładnie tak samo jak zapisy w aplikacji: uruchamiają się Business Events, działa walidacja, a otwarte ekrany się odświeżają.

Wywołaj Script Module

Niektóre endpointy uruchamiają Script Module zamiast udostępniać wiersze encji, do pracy, która wykracza poza odczyt lub zapis: wyceny zamówienia, rezerwacji terminu, raportu. Każda wersja takiego endpointu odpowiada na jedną metodę, a dokument OpenAPI mówi, na którą: POST przyjmuje parametry jako obiekt JSON w ciele żądania, GET w parametrach URL-a.

# A version called with POST: the parameters as a JSON object
curl -X POST "$API/api/data/v1/quote" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"quantity": 3, "express": true}'

# A version called with GET: the parameters in the query string
curl "$API/api/data/v1/planner-week?weekStart=2026-09-21" \
  -H "Authorization: Bearer $TOKEN"

Odpowiedzią jest to, co zwraca moduł, w formacie JSON:

{
  "quantity": 3,
  "total": 172.5,
  "deliveryDate": "2026-09-28"
}
  • Nazwy parametrów to te, które administrator nadał wersji. Każda wartość jest sprawdzana względem swojego typu, zanim moduł się uruchomi: liczba całkowita, liczba, true lub false, data z godziną lub bez (2026-09-25, 2026-09-25T14:30:00Z) albo tekst. Wartość złego typu, parametr, którego wersja nie zna, i brakujący parametr wymagany dają 400; null liczy się jako pominięty.
  • Moduł, który nic nie zwraca, odpowiada 204 No Content. Moduł, który zawiedzie, odpowiada 500 z własnym komunikatem modułu w detail.
  • Wywołanie wymaga roli, której na endpoincie przyznano operację Call. Moduł, który administrator oznaczył jako admin only, odpowiada tylko rolom admin i owner, więc klucz API nigdy do niego nie dotrze.
  • Moduł działa naprawdę, dokładnie tak jak wtedy, gdy uruchamia go aplikacja: to, co zapisuje, uruchamia Business Events, a poczta, którą wysyła, naprawdę wychodzi.
  • Wywołanie inną metodą albo na ścieżce elementu, takiej jak /quote/1, daje 405, a nagłówek Allow podaje metodę, której należy użyć.

Utrzymuj sesję użytkownika

Dotyczy to tylko zalogowanego użytkownika, klucz API niczego takiego nie potrzebuje. Zanim token dostępu wygaśnie albo gdy wywołanie zwróci 401, wymień token odświeżania na nową parę:

curl -X POST "$API/api/v1/auth/refresh" \
  -H "Content-Type: application/json" \
  -d '{"refreshToken": "q8Zr0dW3..."}'

Odpowiedź ma ten sam kształt co przy logowaniu, z nowym tokenem odświeżania. Zapisz go i wyrzuć stary: token odświeżania działa tylko raz. Jeśli po upływie minuty ponownie użyjesz już zużytego tokenu, zostanie to potraktowane jako kradzież i cała sesja się zakończy, a potem trzeba będzie zalogować się od nowa. Dlatego daj każdemu procesowi lub workerowi własną sesję i nigdy nie współdziel jednego tokenu odświeżania między nimi.

Odświeżenie zwraca 401, gdy sesja się zakończyła: wygasła, konto zostało wyłączone lub usunięte z przestrzeni roboczej albo nastąpiło wylogowanie. Wtedy zaloguj się ponownie. Zmiany ról trafiają do tokenu przy następnym odświeżeniu, więc odebrana rola przestaje działać w ciągu 15 minut. Aby samodzielnie zakończyć sesję:

curl -X POST "$API/api/v1/auth/logout" \
  -H "Content-Type: application/json" \
  -d '{"refreshToken": "q8Zr0dW3..."}'

Konto w więcej niż jednej przestrzeni roboczej

Logowanie wybiera dla sesji jedną przestrzeń roboczą: tę, do której należy wywoływany adres, jeśli konto jest jej członkiem, a w przeciwnym razie tę, której używało ostatnio. Dlatego dedykowane konto powinno należeć tylko do jednej przestrzeni roboczej. Jeśli należy do kilku, pobierz ich listę i przełącz się, podając tenantId tej, której potrzebujesz:

# The workspaces this account belongs to
curl "$API/api/v1/auth/tenants" -H "Authorization: Bearer $TOKEN"

# A new token pair for one of them
curl -X POST "$API/api/v1/auth/switch-tenant" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tenantId": "3f1c2a9e-..."}'

Przełączenie zwraca nową parę tokenów dla tej przestrzeni roboczej, dalej pracuj z nią tak jak po zalogowaniu.

Filtrowanie, sortowanie i stronicowanie

# Customers whose name contains "acme", highest credit limit first
curl -G "$API/api/data/v1/customers" \
  -H "Authorization: Bearer $TOKEN" \
  --data-urlencode "filter[name][like]=acme" \
  --data-urlencode "filter[creditLimit][gte]=100" \
  --data-urlencode "sort=-creditLimit" \
  --data-urlencode "page=2" \
  --data-urlencode "pageSize=50"
ParametrZnaczenie
pageNumer strony, liczony od 1.
pageSizeLiczba elementów na stronę, domyślnie 50. Każda wersja ustala maksimum (100, o ile administrator go nie zmienił), a prośba o więcej kończy się kodem 400.
sortJedno pole, poprzedzone - dla kolejności malejącej. Bez tego parametru najpierw najnowsze.
searchTekst dopasowywany do każdego pola, które zwraca wersja.
filter[field]Równe podanej wartości.
filter[field][op]Porównanie z użyciem operatora, patrz niżej. Przy kilku filtrach wszystkie muszą być spełnione.
OperatorDopasowuje
eq, neRówne, różne.
gt, gte, lt, lteWiększe lub mniejsze niż. Liczby, daty i tekst.
like, startswith, endswithTekst, który zawiera wartość, zaczyna się od niej lub na niej kończy, bez rozróżniania wielkości liter. Tylko pola tekstowe.
inDowolna wartość z listy rozdzielonej przecinkami: filter[id][in]=1,2,3.
nulltrue dla pustych wartości, false dla wypełnionych.

Wartości są sprawdzane pod kątem typu pola, więc filter[creditLimit]=lots daje 400 ze wskazaniem pola. Filtrować, sortować i przeszukiwać można tylko pola, które zwraca wersja, a nieznany parametr jest odrzucany, a nie ignorowany, więc literówka nigdy po cichu nie zwróci wszystkiego. Parametry zaczynające się od _ są ignorowane, więc możesz ich użyć do omijania cache.

Wersje

Wersja jest częścią ścieżki, a kilka wersji jednego endpointu może działać równolegle. Opublikowana wersja nigdy nie zmienia się w sposób, który psuje integrację: pola nigdy nie są usuwane ani przemianowywane i nic nie staje się wymagane. Tak samo wersja, która wywołuje Script Module, zachowuje swoją metodę i parametry i zyskuje tylko parametry opcjonalne. Takie zmiany trafiają do nowej wersji.

  • Wersje Active i Deprecated odpowiadają.
  • Wersja, która nie istnieje albo wciąż ma status Draft, zwraca 404 i wymienia wersje, które istnieją.
  • Wersja Retired zwraca 410 Gone i wskazuje tę, na którą należy przejść.

Każda odpowiedź podaje, jakie wersje istnieją. Wersja Deprecated dodatkowo to zaznacza i mówi, kiedy zniknie:

HTTP/1.1 200 OK
api-supported-versions: 1, 2
api-deprecated-versions: 1
Deprecation: @1788220800
Sunset: Thu, 31 Dec 2026 00:00:00 GMT
Link: <https://api.example.com/api/data/v2/customers>; rel="successor-version"

Deprecation to moment, w którym wersja dostała status Deprecated (czas Unix), Sunset to data, od której przestanie odpowiadać, jeśli administrator ją ustawił, a Link wskazuje następną wersję. Zapisywanie ostrzeżenia w logach za każdym razem, gdy pojawi się Deprecation, to najprostszy sposób, żeby dowiedzieć się o tym na czas.

Błędy

Odmowa z Data API to standardowy dokument Problem Details (RFC 7807), którego pole detail mówi, co było nie tak:

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json

{
  "title": "Forbidden",
  "status": 403,
  "detail": "None of your roles may Delete on 'customers'."
}

Jeden wyjątek: gdy walidacja Business Event odrzuci zapis, ciało odpowiedzi 422 ma postać { "message": "...", "errorColumns": [...] } i wskazuje błędne pola nazwami kolumn z samej bazy danych.

StatusZnaczenie
400Żądanie jest niepoprawne: nieznane pole lub parametr, wartość złego typu, brak wymaganego pola.
401Brak tokenu lub klucza albo nie jest on już ważny. Użytkownik odświeża token i ponawia żądanie; klucz API wygasł, został wymieniony w ramach rotacji albo jego klient został wyłączony lub usunięty.
403Żadna z ról konta nie pozwala na tę operację na tym endpoincie.
404Nie ma takiego endpointu, wersji ani elementu.
405Ta wersja nie oferuje tej operacji, np. usuwania, albo endpoint Script Module wywołano inną metodą.
409Konflikt danych: taka unikalna wartość już istnieje albo inne rekordy wciąż odwołują się do tego.
410Wersja została wycofana (Retired).
422Reguła biznesowa lub reguła tabeli odrzuciła wartości.
429Zbyt wiele żądań. Odczekaj chwilę i spróbuj ponownie.
500Script Module za endpointem zawiódł; detail zawiera jego komunikat.

Opis OpenAPI

GET /api/data/openapi.json, wywołany z twoim tokenem, zwraca dokument OpenAPI 3 opisujący dokładnie te wersje i operacje, z których może korzystać twoje konto, wraz z każdym polem i jego typem. Zaimportuj go do Postmana lub Insomnii albo wygeneruj z niego typowanego klienta. Pobierz go ponownie, gdy administrator opublikuje nową wersję.

Przykłady w Pythonie

Z kluczem API wystarczy sam nagłówek:

import os
import requests

API = os.environ["ARCHESTACK_API"]
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['ARCHESTACK_API_KEY']}"

r = session.get(f"{API}/api/data/v1/customers", params={"pageSize": 100}, timeout=30)
r.raise_for_status()
for customer in r.json()["items"]:
    print(customer["id"], customer["name"])

Po zalogowaniu jako użytkownik trzeba zadbać o sesję. Ten przykład loguje się, odświeża token minutę przed jego wygaśnięciem, radzi sobie z 401, odczytuje wszystkie strony i tworzy element. Adres i dane logowania umieść w zmiennych środowiskowych.

import os
import time
import requests

API = os.environ["ARCHESTACK_API"]            # e.g. https://api.example.com
EMAIL = os.environ["ARCHESTACK_EMAIL"]
PASSWORD = os.environ["ARCHESTACK_PASSWORD"]


class DataApi:
    """One signed-in session. Give every process or worker its own."""

    def __init__(self):
        self.token = None
        self.refresh_token = None
        self.expires_at = 0.0

    def _keep(self, body):
        self.token = body["token"]
        self.refresh_token = body["refreshToken"]  # always replace it: each one works once
        self.expires_at = time.time() + body["expiresIn"] - 60

    def sign_in(self):
        r = requests.post(f"{API}/api/v1/auth/login",
                          json={"email": EMAIL, "password": PASSWORD}, timeout=30)
        r.raise_for_status()
        self._keep(r.json())

    def refresh(self):
        r = requests.post(f"{API}/api/v1/auth/refresh",
                          json={"refreshToken": self.refresh_token}, timeout=30)
        if r.status_code == 401:  # the session ended: start a new one
            return self.sign_in()
        r.raise_for_status()
        self._keep(r.json())

    def call(self, method, path, **kwargs):
        if self.token is None:
            self.sign_in()
        elif time.time() >= self.expires_at:
            self.refresh()
        r = self._send(method, path, **kwargs)
        if r.status_code == 401:  # expired early or revoked: refresh once and retry
            self.refresh()
            r = self._send(method, path, **kwargs)
        return r

    def _send(self, method, path, **kwargs):
        headers = {"Authorization": f"Bearer {self.token}"}
        return requests.request(method, f"{API}/api/data{path}",
                                headers=headers, timeout=30, **kwargs)


api = DataApi()

# Every page of customers
page = 1
while True:
    r = api.call("GET", "/v1/customers", params={"page": page, "pageSize": 100})
    r.raise_for_status()
    body = r.json()
    for customer in body["items"]:
        print(customer["id"], customer["name"])
    if page * body["pageSize"] >= body["totalCount"]:
        break
    page += 1

# Create one
r = api.call("POST", "/v1/customers", json={"name": "Hooli", "email": "hi@hooli.test"})
if r.status_code == 201:
    print("created", r.json()["id"])
else:
    print("refused:", r.json().get("detail"))
Środowiska trial: API mogą tam wywoływać tylko konto właściciela trialu oraz każdy API client, którego ten właściciel utworzy.

Dokąd dalej

  • Business Entities - z czego czyta endpoint i dlaczego encja złączona z tabelą jeden-do-wielu zwraca jeden element na każdy złączony wiersz.
  • User Management - utwórz konto integracji i jego rolę.