Integracja API

Praktyczny przewodnik z przykładami do skopiowania, który pokazuje integrację z API GraphQL Gibbond — z systemu zaplecza, aplikacji mobilnej lub internetowej albo innego kanału sprzedaży. Pełny schemat znajdziesz w referencji API.

Na tej stronie
⚡

Plan Pro. Utwórz klucz API na stronie Klucze API w panelu administracyjnym Gibbond, a następnie przechowuj go w zmiennej środowiskowej serwera. Poniższe przykłady zakładają, że GIBBOND_API_KEY zawiera klucz z zakresem WRITE.

Jak to działa

Są dwa rodzaje danych uwierzytelniających — najważniejsze jest, by wybrać właściwy:

  • Klucz API (glk_live_…) — identyfikuje Twoje zaplecze. Umożliwia odczyt i zapis danych wszystkich członków, dlatego należy przechowywać go wyłącznie na serwerze. Używaj go do komunikacji między serwerami i tworzenia tokenów klienta.
  • Token klienta — krótkotrwałe dane uwierzytelniające ograniczone do jednego klienta. Twoje zaplecze tworzy go za pomocą klucza API i przekazuje klientowi (przeglądarce lub aplikacji). Klient może wtedy wyświetlać dane i wykonywać działania tylko na koncie tej osoby, więc token można bezpiecznie przekazać na urządzenie.

Wybierz odpowiedni sposób integracji

Tworzysz…UżyjPrzejdź do
Proces zaplecza, synchronizację z systemem ERP lub backend headlessBezpośrednio klucza APIZ backendu
Aplikację mobilną lub jednostronicową aplikację pokazującą członkowi jego punktyKlucza API na serwerze → tokenu klienta na urządzeniuW aplikacji
System POS, marketplace lub checkout headless, w którym klienci mają zdobywać punktyKlucz API, awardPointsForOrderZ innego kanału

Funkcja pomocnicza do żądań

Każde wywołanie ma ten sam format, dlatego warto opakować je w funkcję. Poniższy przykład dla Node.js korzysta z wbudowanego fetch (Node 18+):

// gibbond.js
const ENDPOINT = "https://app.gibbond.com/api/v1/graphql";

export async function gibbond(query, variables, token) {
  const res = await fetch(ENDPOINT, {
    method: "POST",
    headers: {
      "Authorization": "Bearer " + token,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query, variables }),
  });

  if (res.status === 429) {
    const retryAfter = Number(res.headers.get("Retry-After") || 1);
    const err = new Error("Rate limited");
    err.retryAfter = retryAfter;
    throw err;
  }

  const json = await res.json();
  if (json.errors && json.errors.length) {
    const code = json.errors[0].extensions && json.errors[0].extensions.code;
    throw new Error(code + ": " + json.errors[0].message);
  }
  return json.data;
}

Sposób 1 — z backendu (komunikacja między serwerami)

Za pomocą klucza WRITE możesz wykonywać operacje na każdym członku swojego sklepu. Zapisz klienta do programu lojalnościowego, odczytaj jego dane i przyznaj mu punkty:

import { gibbond } from "./gibbond.js";
const KEY = process.env.GIBBOND_API_KEY;
const id = "gid://shopify/Customer/123456789";

// Enroll a customer (idempotent — safe to call again).
await gibbond(
  "mutation($id: ID!, $email: String) { enrollCustomer(customerId: $id, email: $email) { ok customer { enrolled } } }",
  { id, email: "ada@example.com" },
  KEY,
);

// Read their balance and tier.
const { customer } = await gibbond(
  "query($id: ID!) { customer(id: $id) { balance pending lifetime tier { name multiplier } } }",
  { id },
  KEY,
);

// Grant points. idempotencyKey makes retries safe — the same key never double-applies.
await gibbond(
  "mutation($id: ID!, $pts: Int!, $k: String) { awardPoints(customerId: $id, points: $pts, reason: \"Newsletter signup\", idempotencyKey: $k) { ok pointsApplied balance { balance } } }",
  { id, pts: 100, k: "newsletter-123456789" },
  KEY,
);
ℹ️

Ujemna wartość w mutacji awardPoints oraz wywołanie clawbackPoints wymagają klucza ADMIN — do tych operacji używaj osobnego, ściśle chronionego klucza.

Sposób 2 — w aplikacji mobilnej lub internetowej

Nigdy nie umieszczaj klucza API w aplikacji. Udostępnij na własnym serwerze niewielki punkt końcowy, który tworzy token klienta dla zalogowanego użytkownika, a następnie pozwól aplikacji komunikować się bezpośrednio z Gibbond za pomocą tego tokenu.

Skąd wziąć GID klienta?

Token klienta jest powiązany z GID przekazanym do mintCustomerToken — dlatego musisz utworzyć go dla właściwego klienta. Gibbond uwierzytelnia Twoje zaplecze (za pomocą klucza API), ale nie uwierzytelnia kupującego. Zanim utworzysz token, serwer musi już wiedzieć i mieć pewność, który klient Shopify jest zalogowany. Można to ustalić na trzy sposoby, uporządkowane według preferencji:

Sposób logowania kupującego w aplikacjiŹródło GID
Shopify Customer Account API (zalecane)Zaloguj kupującego przez oparty na OAuth mechanizm Shopify: Customer Account API. Backend wymienia otrzymany token na zweryfikowaną tożsamość klienta i odczytuje jego GID. Tożsamość jest weryfikowana przez Shopify na całej drodze.
Interfejs natywny dla ShopifyJeśli interfejs działa wewnątrz Shopify (jako osadzenie aplikacji w motywie lub rozszerzenie UI konta klienta), Shopify udostępnia już podpisaną tożsamość — odczytaj ją z proxy aplikacji (logged_in_customer_id) lub pola sub tokenu sesji konta klienta. Odczytaj ją po stronie serwera i użyj tego GID.
Własny system logowaniaW kanale z własnymi kontami (np. aplikacji niestandardowej lub systemie POS) przypisz użytkownika do GID klienta Shopify, korzystając z mapowania zapisanego podczas tworzenia konta. To Ty potwierdzasz to powiązanie, dlatego starannie zabezpiecz ten mechanizm.
✅

Zalecane: Customer Account API. W sklepie headless lub aplikacji mobilnej uwierzytelniaj kupujących za pomocą Customer Account API i pobieraj GID ze zweryfikowanego tokenu Shopify. Dzięki temu cały łańcuch — kupujący → tożsamość zweryfikowana przez Shopify → backend → utworzony token klienta — jest zaufany z założenia i nie musisz zabezpieczać własnego mapowania GID. Middleware requireAuth w przykładzie poniżej to właściwe miejsce na tę weryfikację.

ℹ️

Jeśli interfejs działa już wewnątrz sesji Shopify (jako blok motywu, checkoutu lub konta klienta), zwykle nie potrzebujesz tego API — bloki aplikacji w sklepie w motywie i integracja z kontem klienta weryfikują tożsamość Shopify za Ciebie. Korzystaj z tokenów klienta, gdy działasz poza takim środowiskiem.

Na serwerze

Własny mechanizm uwierzytelniania informuje, który klient Shopify jest zalogowany (jego GID). Utwórz dla niego token:

import express from "express";
import { gibbond } from "./gibbond.js";

const app = express();

// requireAuth is YOUR session middleware; it sets req.customerGid.
app.post("/loyalty/session", requireAuth, async (req, res) => {
  const data = await gibbond(
    "mutation($id: ID!) { mintCustomerToken(customerId: $id, ttlSeconds: 900) { token expiresAt } }",
    { id: req.customerGid },
    process.env.GIBBOND_API_KEY, // WRITE key, server-side only
  );
  // Hand the app the token, when it expires, and the id it is bound to.
  res.json({
    token: data.mintCustomerToken.token,
    expiresAt: data.mintCustomerToken.expiresAt,
    customerId: req.customerGid,
  });
});

W aplikacji

Pobierz token z serwera, a następnie wywołaj Gibbond bezpośrednio. Zapytanie me zwraca klienta przypisanego do tokenu, więc nie trzeba podawać identyfikatora:

// 1. Get a short-lived token from YOUR backend.
const session = await fetch("/loyalty/session", { method: "POST" }).then(r => r.json());

// 2. Call Gibbond with the customer token.
async function loyalty(query, variables) {
  const res = await fetch("https://app.gibbond.com/api/v1/graphql", {
    method: "POST",
    headers: {
      "Authorization": "Bearer " + session.token,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query, variables }),
  });
  return (await res.json()).data;
}

// Show the member their points, tier, and reward codes.
const { me } = await loyalty("{ me { name balance lifetime tier { name multiplier } } }");
const { activeCodes } = await loyalty(
  "query($id: ID!) { activeCodes(customerId: $id) { code rewardName status expiresAt } }",
  { id: session.customerId },
);

renderRewardsScreen(me, activeCodes);

Wymiana nagrody w aplikacji

Za pomocą tokenu klienta można wymienić nagrodę na własnym koncie — klucz sprzedawcy nie jest potrzebny na urządzeniu. Mutacja zwraca jednorazowy kod rabatowy do zastosowania przy kasie:

const { redeemReward } = await loyalty(
  "mutation($id: ID!, $reward: ID!) { redeemReward(customerId: $id, rewardId: $reward) { ok code { code rewardName pointsSpent expiresAt } } }",
  { id: session.customerId, reward: "gid_or_reward_id_from_rewards_query" },
);
if (redeemReward.ok) applyDiscountCode(redeemReward.code.code);
ℹ️

Domyślnie tokeny są ważne przez 15 minut (wartość ttlSeconds można zwiększyć do 24 godzin). Jeśli wywołanie zwróci błąd UNAUTHENTICATED, ponownie wywołaj /loyalty/session, aby uzyskać nowy token i ponowić żądanie.

Sposób 3 — naliczanie punktów w innym kanale sprzedaży

Gdy zamówienie zostanie złożone poza checkoutem Shopify — w systemie POS, marketplace lub sklepie headless — zgłoś je za pomocą awardPointsForOrder. Gibbond stosuje mnożnik poziomu członka, aktywne boosty i kamienie milowe tak samo jak przy zamówieniu Shopify. Operacja jest idempotentna względem orderId, więc można bezpiecznie ponawiać żądanie:

await gibbond(
  `mutation($input: OrderInput!) {
    awardPointsForOrder(input: $input) {
      ok
      pointsApplied
      balance { balance lifetime }
    }
  }`,
  {
    input: {
      orderId: "pos-2026-000123",
      customerId: "gid://shopify/Customer/123456789",
      customerEmail: "ada@example.com",
      orderName: "POS #000123",
      lineItems: [
        { productId: "gid://shopify/Product/55", collectionIds: ["gid://shopify/Collection/9"], lineTotal: 42.0 },
        { lineTotal: 8.5 },
      ],
    },
  },
  process.env.GIBBOND_API_KEY,
);

Każda pozycja zamówienia może zawierać opcjonalne pola productId i collectionIds oraz wymaganą wartość lineTotal — boosty i wykluczenia dla produktów oraz kolekcji działają tak samo jak przy zamówieniach Shopify. Aby później potwierdzić punkty (np. po realizacji zamówienia), wywołaj confirmPoints(customerId, orderId); aby cofnąć punkty po zwrocie środków, wywołaj clawbackPoints z kluczem ADMIN.

Błędy, ponowienia i idempotencja

  • Kody. Błędy są zwracane w tablicy GraphQL errors; odczytaj errors[0].extensions.code — UNAUTHENTICATED (401), FORBIDDEN (403, niewłaściwy zakres), RATE_LIMITED (429), BAD_USER_INPUT (400), NOT_FOUND (404).
  • Limity zapytań. 600 żądań na minutę dla każdych danych uwierzytelniających. Po otrzymaniu 429 odczekaj liczbę sekund podaną w nagłówku Retry-After, a następnie ponów żądanie.
  • Idempotencja. Przekaż klucz idempotencyKey do mutacji awardPoints i stały identyfikator orderId do awardPointsForOrder. Ponowne wysłanie tego samego klucza lub zamówienia nie spowoduje podwójnego naliczenia, więc można swobodnie ponawiać żądania po błędach sieci.
  • Wygaśnięcie tokenu. Błąd UNAUTHENTICATED dla tokenu klienta oznacza, że trzeba utworzyć nowy token i ponowić żądanie.

Zasady bezpieczeństwa

  • Przechowuj klucze API wyłącznie w bezpiecznych zmiennych serwera — nigdy w pakiecie aplikacji, kodzie przeglądarkowym ani systemie kontroli wersji.
  • Używaj tokenu klienta do operacji wykonywanych na urządzeniu; nigdy nie umieszczaj tam klucza API.
  • Przyznawaj każdej integracji najniższy wymagany zakres (klucz READ do paneli, WRITE do naliczania i wymiany punktów, a ADMIN wyłącznie do zwrotów i korekt).
  • Wymień klucz w panelu administracyjnym, gdy tylko podejrzewasz jego wyciek — cofnięcie uprawnień działa natychmiast.
  • Twórz tokeny klienta z możliwie najkrótszym czasem ważności ttlSeconds.

Pełną listę typów, zapytań, mutacji i pól znajdziesz w referencji API.