API-integration

En praktisk guide med exempel att kopiera för att integrera Gibbonds GraphQL-API — från ett backoffice-system, en mobil- eller webbapp eller en annan försäljningskanal. Hela schemat finns i API-referensen.

På den här sidan
⚡

Pro-planen. Skapa en API-nyckel på sidan API-nycklar i Gibbonds admin och förvara den i en miljövariabel på servern. Exemplen nedan förutsätter att GIBBOND_API_KEY innehåller en WRITE-nyckel.

Så hänger delarna ihop

Det finns två typer av autentiseringsuppgifter, och det är viktigt att välja rätt:

  • API-nyckel (glk_live_…) — identifierar din backend. Den kan läsa och ändra alla medlemmars uppgifter och får därför bara finnas på din server. Använd den för kommunikation mellan servrar och för att skapa kundtoken.
  • Kundtoken — en kortlivad autentiseringsuppgift begränsad till en kund. Din backend skapar den med API-nyckeln och skickar den till en klient (webbläsare eller app). Klienten kan bara se och utföra åtgärder för den kunden, så tokenen kan skickas säkert till enheten.

Välj integrationssätt

Du bygger…AnvändGå till
Ett backoffice-jobb, en ERP-synkronisering eller en headless-backendAPI-nyckeln direktFrån din backend
En mobil- eller ensidesapp som visar en medlem deras poängAPI-nyckel på servern → kundtoken på enhetenI en app
Ett kassasystem, en marknadsplats eller en headless-kassa där kunder ska tjäna poängAPI-nyckel, awardPointsForOrderFrån en annan kanal

En hjälpfunktion för anrop

Alla anrop har samma format, så samla dem i en hjälpfunktion. Det här Node-exemplet använder inbyggd 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;
}

Mönster 1 — från din backend (server till server)

Med en WRITE-nyckel kan du utföra åtgärder för alla medlemmar i din butik. Registrera en kund, läs deras uppgifter och tilldela poäng:

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,
);
ℹ️

Ett negativt belopp för awardPoints och anrop till clawbackPoints kräver en ADMIN-nyckel — använd separata, noggrant skyddade autentiseringsuppgifter för dessa flöden.

Mönster 2 — i en mobil- eller webbapp

Lägg aldrig API-nyckeln i en app. Skapa i stället en liten slutpunkt på din egen server som skapar en kundtoken för den inloggade användaren. Låt sedan appen kommunicera direkt med Gibbond med tokenen.

Varifrån kommer kundens GID?

En kundtoken binds till det GID du skickar till mintCustomerToken — du ansvarar alltså för att skapa den för rätt kund. Gibbond autentiserar din backend via API-nyckeln, men autentiserar inte slutkunden. Innan tokenen skapas måste din server redan veta och kunna lita på vilken Shopify-kund som är inloggad. Det kan fastställas på tre sätt, i prioritetsordning:

Så loggar appen in kundenVarifrån GID hämtas
Shopify Customer Account API (rekommenderas)Logga in kunden med Shopifys OAuth-baserade Customer Account API. Din backend använder den resulterande tokenen för att hämta den verifierade kunden och läsa deras GID. Identiteten är signerad av Shopify genom hela kedjan.
Ett gränssnitt inbyggt i ShopifyOm upplevelsen körs i Shopify (en appinbäddning i temat eller ett tillägg för kundkontot) tillhandahåller Shopify redan den signerade identiteten — app-proxyns logged_in_customer_id eller fältet sub i kundkontots sessionstoken. Läs värdet på servern och använd detta GID.
Din egen inloggningEn kanal med egna konton (en anpassad app eller ett kassasystem) kopplar användaren till ett Shopify-kund-GID med en mappning som du sparade när kunden skapades. Du ansvarar för kopplingen, så skydda den här vägen noggrant.
✅

Rekommenderat: Customer Account API. För en headless-butik eller mobilapp autentiserar du kunder med Shopifys Customer Account API och hämtar GID från Shopifys verifierade token. Då är hela kedjan — kund → Shopify-verifierad identitet → din backend → skapad kundtoken — tillförlitlig från början, utan någon GID-mappning att skydda. Kontrollera detta i mellanprogramvaran requireAuth nedan.

ℹ️

Om ditt gränssnitt redan körs inom Shopifys session (ett tema-, kassa- eller kundkontoblock) behöver du vanligtvis inte detta API — butikens appblock och integrationen för kundkonton verifierar Shopify-identiteten åt dig. Använd kundtoken när du arbetar utanför det sammanhanget.

På din server

Din egen autentisering anger vilken Shopify-kund som är inloggad (deras GID). Skapa en token för kunden:

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,
  });
});

I appen

Hämta en token från din server och anropa sedan Gibbond direkt. Frågan me avser kunden som tokenen tillhör — inget id behövs:

// 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);

Lös in belöningar i appen

En kundtoken kan lösa in en belöning för sin egen kund — ingen handlar-nyckel behövs på enheten. Mutationen returnerar en engångsrabattkod som kan användas i kassan:

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);
ℹ️

Token är giltiga i 15 minuter som standard (ställ in ttlSeconds upp till 24 timmar). Om ett anrop returnerar UNAUTHENTICATED, anropa /loyalty/session igen för en ny token och försök på nytt.

Mönster 3 — tjäna poäng från en annan försäljningskanal

När en beställning sker utanför din Shopify-kassa — i ett kassasystem, på en marknadsplats eller i en headless-butik — rapporterar du den med awardPointsForOrder. Gibbond tillämpar medlemmens nivåmultiplikator, aktiva Boosts och milstolpar precis som för en Shopify-beställning. Anropet är idempotent för orderId, så omförsök är säkra:

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,
);

Varje orderrad har ett valfritt productId, valfria collectionIds och ett obligatoriskt lineTotal — produkt- och kollektionsspecifika Boosts och undantag fungerar därför som för Shopify-beställningar. För att bekräfta poäng senare (t.ex. efter att beställningen har distribuerats), anropa confirmPoints(customerId, orderId); för att återföra dem vid en återbetalning, anropa clawbackPoints med en ADMIN-nyckel.

Fel, omförsök och idempotens

  • Koder. Fel returneras i en GraphQL-array med namnet errors; läs errors[0].extensions.code — UNAUTHENTICATED (401), FORBIDDEN (403, fel behörighetsomfång), RATE_LIMITED (429), BAD_USER_INPUT (400), NOT_FOUND (404).
  • Anropsbegränsningar. 600 anrop per minut per autentiseringsuppgift. Vid 429, vänta det antal sekunder som anges i Retry-After-headern och försök sedan igen.
  • Idempotens. Skicka en idempotencyKey till awardPoints och ett stabilt orderId till awardPointsForOrder. Samma nyckel eller beställning tillämpas aldrig dubbelt — du kan därför försöka igen vid nätverksfel.
  • Utgången token. Om en kundtoken ger UNAUTHENTICATED, skapa en ny och försök igen.

Säkerhetschecklista

  • Förvara API-nycklar enbart som hemligheter på servern — aldrig i app-paket, webbläsarkod eller versionshantering.
  • Använd en kundtoken för allt som körs på en enhet; aldrig en API-nyckel.
  • Ge varje integration lägsta nödvändiga behörighetsomfång (en READ-nyckel för instrumentpaneler, WRITE för att tjäna och lösa in poäng, ADMIN bara för återbetalningar och korrigeringar).
  • Byt ut nyckeln i admin så snart den kan ha läckt — återkallandet gäller omedelbart.
  • Skapa kundtoken med kortast möjliga praktiska ttlSeconds.

Hela listan över typer, frågor, mutationer och fält finns i API-referensen.