Thulium

Integracja - Własny esklep

Łukasz Strumiński
Łukasz Strumiński
Aktualizacja: 29.10.2026

Wprowadzenie#

Twój sklep internetowy, Twoje zasady – jedna platforma do obsługi klientów!

Nie korzystasz z jednej z popularnych platform e-commerce? A może Twój sklep działa na autorskim oprogramowaniu? Zintegruj go z Thulium i zapewnij konsultantom wygodny dostęp do informacji o zamówieniach, bez konieczności przełączania się między systemami.

Dzięki integracji Własny esklep możesz połączyć Thulium z dowolnym sklepem internetowym udostępniającym odpowiednie API. Konsultanci zyskują dostęp do historii zamówień, ich statusów i szczegółów zakupów bezpośrednio podczas obsługi klienta.

Mniej przełączania między systemami, szybsze odpowiedzi i pełniejszy kontekst każdej rozmowy.


Zakres integracji#

Połączenie własnego sklepu internetowego z Thulium pozwala konsultantom szybciej docierać do informacji zakupowych i sprawniej obsługiwać klientów, niezależnie od kanału kontaktu.

  • Historia zamówień zawsze pod ręką – sprawdzaj zamówienia klienta wraz ze statusami, datami, kosztami, zakupionymi produktami i adresami dostawy bezpośrednio w Thulium.
  • Ostatnie zamówienie w zasięgu wzroku – szybko uzyskaj kontekst ostatnich zakupów klienta, aby sprawniej odpowiadać na pytania dotyczące realizacji zamówienia.
  • Szybki dostęp do szczegółów w sklepie – przechodź bezpośrednio do wybranego zamówienia w panelu sklepu, bez konieczności jego ręcznego wyszukiwania.
  • Wiele sklepów w jednym miejscu – połącz z Thulium kilka sklepów internetowych, np. B2B i B2C, i wygodnie rozpoznawaj źródło poszczególnych zamówień.

Integracja jest przeznaczona dla sklepów, które mają własne oprogramowanie lub platformę bez gotowej integracji z Thulium. Jeśli Twoja platforma jest na liście integracji, wygodniej będzie użyć gotowej.


Krok po kroku#

  1. Przejdź do Administracja → Integracje i wybierz Własny esklep.
  1. W sekcji uwierzytelniania uzupełnij wymagane pola.

gdzie:

  • Adres URL sklepu – adres Twojego sklepu, musi zaczynać się od https:// – login i hasło są przesyłane do sklepu, więc połączenie musi być szyfrowane.
    Login – login do API sklepu.
    Hasło – hasło do API sklepu.
  1. Kliknij przycisk uwierzytelnienia. Thulium połączy się ze sklepem i sprawdzi, czy odpowiada poprawnie.
  1. Uzupełnij pole Nazwa integracji, aby agenci mogli łatwo rozpoznać, z którego sklepu pochodzi zamówienie – szczególnie jeśli korzystasz z kilku sklepów. Następnie kliknij Zapisz i uruchom, aby zapisać ustawienia i aktywować integrację. Możesz ją również uruchomić później za pomocą suwaka aktywacji.

Jeśli zmienisz adres, login lub hasło po uwierzytelnieniu, integracja przestaje być oznaczona jako uwierzytelniona i trzeba uwierzytelnić ją ponownie.

🚀 Gotowe – od teraz zamówienia klientów pojawią się w Thulium.


Informacje o zamówieniach w Thulium#

Wszystkie najważniejsze informacje o zakupach klienta w jednym miejscu! Dzięki integracji konsultanci mogą sprawdzać szczegóły zamówień bezpośrednio w Thulium, zarówno z poziomu historii kontaktu, jak i podczas obsługi rozmowy.

Thulium wyszukuje zamówienia po adresie e-mail klienta. Jeśli klient nie ma zapisanego e-maila, system użyje jego numeru telefonu. Gdy klient nie ma ani e-maila, ani numeru telefonu, zamówień nie da się wyszukać i lista będzie pusta.

Dla każdego zamówienia dostępne są następujące informacje:

  • numer zamówienia i jego status (dokładnie taki, jaki zwraca sklep),
  • data zamówienia,
  • koszt całkowity, koszt produktów i koszt dostawy,
  • lista produktów z ilościami,
  • adres dostawy (miasto, kod pocztowy, ulica, kraj),
  • odnośnik do zamówienia w sklepie.

Dzięki temu konsultant ma pod ręką informacje potrzebne do sprawnej obsługi pytań o zamówienia, bez konieczności każdorazowego otwierania panelu sklepu.

Historia kontaktu:

Kanał kontaktu:


Wymagania wobec API#

Thulium wywołuje Twój sklep pod adresem podanym w polu Adres URL sklepu, przekazując login i hasło (według opisu twórców integracji: jako uwierzytelnianie HTTP Basic).

Rejestracja – POST /thulium/integrations/register

Thulium wysyła w treści JSON identyfikator integracji (id), nazwę klienta (client) i opcjonalnie redirectUrl. Odpowiedź sklepu decyduje o dalszym przebiegu:

  • 200 lub 204 – rejestracja zakończona od razu, system sprawdza następnie, czy sklep poprawnie zwraca zamówienia.
  • Inna odpowiedź – integracja zostanie oznaczona jako nieudana.

Zamówienia – GET /thulium/integrations/orders

Nagłówek X-Thulium-Integration-Id zawiera identyfikator integracji. Parametry: email lub phoneNumber, page (numeracja od 0), size oraz opcjonalnie sort. Sklep zwraca JSON:

  • orders – lista zamówień, page, size.
  • Każde zamówienie: id, status, orderDate (czas UTC w formacie 2026-01-31T12:00:00Z), totalCosts, productsCosts, shippingCosts (obiekty z amount jako tekst, np. "12.50", i currency jako trzyliterowy kod, np. PLN), products (lista z name i quantity ≥ 1), orderUrl (adres zamówienia w sklepie) oraz shippingAddress (city, postcode, street, country).
  • Pola tekstowe nie mogą być puste.

Podczas uwierzytelniania Thulium pobiera jedno zamówienie bez filtrów, żeby sprawdzić format odpowiedzi – sklep musi więc obsłużyć zapytanie bez email i phoneNumber.

Specyfikacja API#

openapi: 3.1.0

info:
  title: Thulium E-commerce Integration API
  version: 1.2.0
  summary: >-
    Contract implemented by a partner shop so that Thulium can register an integration
    and read orders from it.
  description: |
    This specification describes **two endpoints your shop implements** so that Thulium can
    connect to it, plus **one callback Thulium exposes** for you to call back when a client
    finishes configuration on your side.

    ## What you need to build

    | Endpoint | Purpose |
    |---|---|
    | `POST /thulium/integrations/register` | Register a new integration for one Thulium client |
    | `GET /thulium/integrations/orders` | Return orders of a given customer |

    ## Fixed paths

    The paths above are a **convention, not configuration**. Thulium asks the client only for
    a base URL and always appends these exact paths to it. There is no way to point Thulium at
    different paths, so expose them verbatim under whatever host you give the client.

    Example: base URL `https://shop.example.com/api` means Thulium will call
    `https://shop.example.com/api/thulium/integrations/register`.

    ## Authentication

    Both endpoints are called server-to-server by Thulium with HTTP Basic authentication.
    Only HTTPS is supported. Which credentials are sent depends on who runs the shop:

    * **A shop serving a single Thulium client** — credentials the client entered in the
      Thulium panel.
    * **A partner serving many Thulium clients from one deployment** — one set of credentials
      agreed between the partner and Thulium, the same for every client.

    ## Identifying the client

    Every call to the orders endpoint carries the `X-Thulium-Integration-Id` header with the
    `id` Thulium sent at registration. It stays the same for the lifetime of the integration,
    including when the client registers it again.

    A shop serving a single client may ignore it. A partner serving many clients uses it to pick
    the installation: the credentials are shared, so the header is the only thing that says whose
    orders to return. Bind the `id` to an installation on your configuration screen (the `302`
    flow below), where the shop owner signs in, and answer `401` for an `id` you have not bound.

    ## Two registration flows

    Your response to registration decides which flow applies:

    * **`200 OK`** — nothing more is needed. Thulium immediately validates the connection by
      fetching one order, and the integration becomes active.
    * **`302 Found`** with a `Location` header — the client must finish configuration on a
      screen you host. Thulium sends the client to that address, then waits for you to call
      the callback. The `Location` host **must** match the host of the client's base URL;
      a redirect to any other host is rejected.

    A partner serving many clients **must** use the `302` flow — the configuration screen is the
    only point at which it learns which installation the `id` belongs to.

  contact:
    name: Thulium
    url: https://thulium.com

servers:
  - url: "{baseUrl}"
    description: Base URL the client configures in the Thulium panel.
    variables:
      baseUrl:
        default: https://shop.example.com/api

security:
  - basicAuth: []

tags:
  - name: Registration
    description: Connecting a Thulium client to your shop.
  - name: Orders
    description: Reading orders for an agent handling a conversation.

paths:

  /thulium/integrations/register:
    post:
      tags: [Registration]
      operationId: registerIntegration
      summary: Register a new integration
      description: |
        Called once, when a Thulium client connects your shop.

        Respond with `200 OK` if there is nothing for the client to do, or with `302 Found`
        and a `Location` header if the client has to complete configuration on your side.
        If you serve many clients, always respond with `302` and bind `id` to the installation
        on that screen.

        The same `id` may arrive again when the client retries a failed or expired registration.
        Replace the previous binding rather than rejecting it.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RegistrationRequest"
      responses:
        "204":
          description: |
            Registration complete — nothing more is required from the client.
        "302":
          description: |
            The client must finish configuration on a screen you host. Thulium hands `Location`
            to its own UI, which sends the client there, and then waits for the callback.

            Only the `Location` header is read — a response body, if you send one, is ignored.
            `302` is the canonical response, but any `3xx` carrying `Location` is treated the
            same way. A `3xx` without `Location` fails the registration.
          headers:
            Location:
              required: true
              description: |
                Absolute or relative address of your configuration screen. Must be `https`,
                and its host must match the host of the client's base URL. A relative
                reference is resolved against the base URL.
              schema:
                type: string
                format: uri-reference
                examples:
                  - https://shop.example.com/setup?ticket=a1b2c3
        "400":
          description: The request was malformed.
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetails"
        "401":
          description: Authentication failed.
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetails"
        "500":
          description: Registration failed on your side.
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetails"
      callbacks:
        configurationCompleted:
          "{$request.body#/redirectUrl}":
            post:
              operationId: notifyConfigurationCompleted
              summary: Tell Thulium the client finished configuration
              description: |
                Call this **only** in the `302` flow, once the client has completed
                configuration on your screen. Send it **server-to-server** — do not redirect
                the client's browser here, because the client may have closed the window
                by then.

                The address is the exact `redirectUrl` you received during registration.
                It already carries an opaque one-time token in its query string; send it back
                unchanged and do not try to interpret, store or reuse it.

                The token is valid for **15 minutes** and works exactly once. Thulium verifies
                the result independently by fetching one order from your orders endpoint before
                activating the integration.
              security: []
              requestBody:
                required: true
                content:
                  application/json:
                    schema:
                      $ref: "#/components/schemas/ConfigurationResult"
              responses:
                "200":
                  description: >-
                    Confirmation accepted and the integration is now active.
                "400":
                  description: >-
                    The token is not recognised (`invalid-state`). Do not retry.
                  content:
                    application/problem+json:
                      schema:
                        $ref: "#/components/schemas/ProblemDetails"
                "409":
                  description: >-
                    The token has already been used (`state-already-used`). The integration
                    was confirmed earlier. Do not retry.
                  content:
                    application/problem+json:
                      schema:
                        $ref: "#/components/schemas/ProblemDetails"
                "410":
                  description: >-
                    The token expired (`state-expired`). More than 15 minutes passed and the client
                    has to start again from the Thulium panel. Do not retry.
                  content:
                    application/problem+json:
                      schema:
                        $ref: "#/components/schemas/ProblemDetails"
                "422":
                  description: >-
                    Confirmation accepted, but the follow-up check against your orders endpoint
                    returned data that does not match this specification (`schema-invalid`).
                    The response body says which field is wrong.
                  content:
                    application/problem+json:
                      schema:
                        $ref: "#/components/schemas/ProblemDetails"

  /thulium/integrations/orders:
    get:
      tags: [Orders]
      operationId: getOrders
      summary: Return orders of a given customer
      description: |
        Returns the orders of a single customer of your shop — the person an agent is currently
        talking to. Thulium calls it during a conversation, and once right after registration
        to validate the connection.

        Identify the customer by `phoneNumber` or `email` — at least one is always sent.
        Return the newest orders first. Thulium fetches a single most-recent order by
        requesting `size=1`, so the same endpoint serves both the list and the "last order" case.

        If the customer is unknown, return `200` with an empty `orders` array — not `404`.
        If the integration is unknown — an `X-Thulium-Integration-Id` you have not bound —
        return `401`. The two must stay distinct: an empty list tells the agent the customer has
        no orders, while `401` tells Thulium the integration itself is broken.
      parameters:
        - name: X-Thulium-Integration-Id
          in: header
          required: true
          description: |
            The `id` Thulium sent at registration, identifying which client's installation the
            request is for. Always sent, including on the validation call right after registration.
            A shop serving a single client may ignore it.
          schema:
            type: string
            format: uuid
            examples: ["7f3a1c62-9e41-4d3b-8a17-0d5b2f9c4e11"]
        - name: phoneNumber
          in: query
          required: false
          description: Customer's phone number, as stored in Thulium. Sent together with or instead of `email`.
          schema:
            type: string
            examples: ["+48123456789"]
        - name: email
          in: query
          required: false
          description: Customer's e-mail address. Sent together with or instead of `phoneNumber`.
          schema:
            type: string
            format: email
            examples: ["jane.doe@example.com"]
        - name: sort
          in: query
          required: false
          description: |
            Sorting instructions as `field,direction` pairs. Repeat the parameter for multiple
            keys; they apply in the order given. Direction is `asc` or `desc`, defaulting to `asc`.
            Ignore fields you cannot sort by rather than failing the request.
          style: form
          explode: true
          schema:
            type: array
            items:
              type: string
              pattern: '^[a-zA-Z]+(,(asc|desc))?$'
            examples:
              - ["orderDate,desc"]
              - ["orderDate,desc", "id,asc"]
        - name: page
          in: query
          required: false
          description: Zero-based page index.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: size
          in: query
          required: false
          description: Page size. Thulium sends `size=1` when it only needs the most recent order.
          schema:
            type: integer
            minimum: 1
            default: 20
      responses:
        "200":
          description: Orders for the given customer. An unknown customer yields an empty array.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Orders"
        "400":
          description: The request was malformed.
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetails"
        "401":
          description: >-
            Authentication failed, or `X-Thulium-Integration-Id` is not bound to any installation.
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetails"
        "500":
          description: The orders could not be read on your side.
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemDetails"

components:

  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: >-
        Sent on every call to both endpoints. HTTPS only. Either the credentials the client
        entered in the Thulium panel, or — for a partner serving many clients — one set agreed
        with Thulium and shared by all of them. Shared credentials authenticate Thulium, not the
        client; the client is identified by `X-Thulium-Integration-Id`.

  schemas:

    RegistrationRequest:
      type: object
      required: [id, client]
      properties:
        id:
          type: string
          format: uuid
          description: >-
            Thulium's identifier for this integration. Sent again in `X-Thulium-Integration-Id`
            on every call to the orders endpoint. If you serve many clients, bind it to the
            installation on your configuration screen; otherwise use it only to correlate your
            own records with Thulium's.
          examples: ["7f3a1c62-9e41-4d3b-8a17-0d5b2f9c4e11"]
        client:
          type: string
          description: Identifier of the Thulium client the integration belongs to.
          examples: ["acme"]
        redirectUrl:
          type: string
          format: uri
          description: |
            Address to call once the client finishes configuration on your side.
            Present only when the client's configuration expects that step; absent when
            registration is meant to complete immediately.

            Treat it as opaque: it already contains a one-time token. Use it verbatim,
            do not append to it and do not store it beyond this registration.
          examples:
            - https://app.thulium.com/api/custom-ecommerce/callback?state=b0Fh2Xq9

    ConfigurationResult:
      type: object
      required: [result]
      properties:
        result:
          type: string
          enum: [ok, error]
          description: >-
            `ok` when the client completed configuration successfully, `error` when it failed
            or the client abandoned it. Thulium verifies `ok` independently before activating
            the integration.
        message:
          type: string
          description: >-
            Optional human-readable detail, shown to the Thulium client when `result` is
            `error`. Do not put secrets here.
          examples: ["The shop has no active API plan"]

    Orders:
      type: object
      required: [orders, page, size]
      properties:
        orders:
          type: array
          description: Orders on this page, newest first. Empty when the customer is unknown.
          items:
            $ref: "#/components/schemas/Order"
        page:
          type: integer
          minimum: 0
          description: Zero-based index of the returned page.
        size:
          type: integer
          minimum: 1
          description: Page size that was applied.

    Order:
      type: object
      required: [id, status, orderDate, totalCosts, products]
      properties:
        id:
          type: string
          description: Order identifier as the customer sees it.
          examples: ["ORD-2026-00123"]
        status:
          type: string
          description: >-
            Order status. The set of allowed values is still being agreed — until it is fixed,
            send your own value and Thulium will display it as-is.
          examples: ["SHIPPED"]
        orderDate:
          type: string
          format: date-time
          description: When the order was placed, with a timezone offset.
          examples: ["2026-08-11T14:32:05+02:00"]
        totalCosts:
          allOf:
            - $ref: "#/components/schemas/Money"
          description: Total amount paid by the customer, including shipping.
        productsCosts:
          allOf:
            - $ref: "#/components/schemas/Money"
          description: Amount for the products alone, excluding shipping. Optional.
        shippingCosts:
          allOf:
            - $ref: "#/components/schemas/Money"
          description: Shipping amount. Optional.
        products:
          type: array
          description: Line items on the order.
          items:
            $ref: "#/components/schemas/Product"
        orderUrl:
          type: string
          format: uri
          description: >-
            Address of the order in your own system, opened by the agent in a new tab. Optional.
          examples: ["https://shop.example.com/admin/orders/ORD-2026-00123"]
        shippingAddress:
          $ref: "#/components/schemas/Address"
        customer:
          $ref: "#/components/schemas/Customer"
        paymentMethod:
          type: string
          pattern: '\S'
          description: >-
            Payment method as shown to the customer. Optional, but must not be blank when sent.
            Thulium may read it out to the caller, so send a human-readable name rather than an
            internal code.
          examples: ["BLIK"]
        deliveryMethod:
          type: string
          pattern: '\S'
          description: >-
            Delivery method as shown to the customer. Optional, but must not be blank when sent.
            Send a human-readable name rather than an internal code.
          examples: ["InPost Paczkomat"]
        trackingNumber:
          type: string
          pattern: '\S'
          description: >-
            Shipment tracking number assigned by the carrier. Optional, but must not be blank
            when sent.
          examples: ["602677016330421016183457"]

    Money:
      type: object
      required: [amount, currency]
      description: |
        Monetary amount, always sent as a pair of value and currency.

        `amount` is a **decimal string**, not a JSON number. Numbers in JSON are read as binary
        floating point by most parsers, which turns `92.12` into something slightly off and makes
        sums drift. A string keeps the value exact all the way through.
      properties:
        amount:
          type: string
          pattern: '^\d+(\.\d{1,4})?$'
          description: >-
            Non-negative decimal value, dot as the separator. No thousands separators, no
            currency symbol, no leading plus. The number of fraction digits should match the
            currency's minor unit — two for `PLN` or `EUR`, none for `JPY`.
          examples: ["92.12"]
        currency:
          type: string
          pattern: '^[A-Z]{3}$'
          description: Currency as an ISO 4217 alpha-3 code, uppercase.
          examples: ["PLN"]

    Product:
      type: object
      required: [name, quantity]
      properties:
        name:
          type: string
          description: Product name as shown to the customer.
          examples: ["Thermal mug 500 ml"]
        quantity:
          type: integer
          minimum: 1
          description: Number of units ordered.
          examples: [2]

    Address:
      type: object
      description: Shipping address. Optional as a whole; send what you have.
      properties:
        street:
          type: string
          examples: ["12 Market Street"]
        city:
          type: string
          examples: ["Warsaw"]
        postcode:
          type: string
          examples: ["00-001"]
        country:
          type: string
          description: Country name or ISO 3166-1 alpha-2 code.
          examples: ["PL"]

    Customer:
      type: object
      description: >-
        Person who placed the order. Optional as a whole; send what you have. A field you send
        must not be blank.
      properties:
        firstName:
          type: string
          pattern: '\S'
          examples: ["Jane"]
        lastName:
          type: string
          pattern: '\S'
          examples: ["Doe"]

    ProblemDetails:
      type: object
      description: |
        Error payload as defined by [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457),
        served with media type `application/problem+json`.

        Branch on `type` — it is the stable, machine-readable identifier. `title` and `detail`
        are meant for humans and may be reworded without notice. Additional extension members
        may appear, so ignore anything you do not recognise rather than failing to parse.
      properties:
        type:
          type: string
          format: uri
          default: "about:blank"
          description: >-
            URI identifying the problem type. Dereferenceable, but treat it as an identifier
            rather than a link.
          examples: ["https://thulium.com/problems/state-expired"]
        title:
          type: string
          description: Short, human-readable summary of the problem type.
          examples: ["Confirmation token expired"]
        status:
          type: integer
          description: HTTP status code, repeated for convenience.
          examples: [410]
        detail:
          type: string
          description: Human-readable explanation specific to this occurrence.
          examples: ["The token expired 4 minutes ago. Ask the client to start again."]
        instance:
          type: string
          format: uri-reference
          description: URI identifying this specific occurrence, useful when reporting issues.
          examples: ["/api/custom-ecommerce/callback/errors/9f21c4"]

Twój sklep, Twoi klienci, wszystkie informacje w jednym miejscu. Połącz własny esklep z Thulium i zapewnij konsultantom dostęp do danych zakupowych, które pomagają szybciej rozwiązywać problemy i budować lepsze doświadczenia klientów.

Czy artykuł był pomocny?

Powiązane artykuły