Integração da API

Guia prático para integrar a API GraphQL do Gibbond, com exemplos para copiar e colar em serviços internos, apps para celular ou web e outros canais de venda. Consulte a referência da API para ver o esquema completo.

Nesta página
⚡

Plano Pro. Crie uma chave de API na página Chaves de API do admin do Gibbond e mantenha-a em uma variável de ambiente no servidor. Os exemplos abaixo pressupõem que GIBBOND_API_KEY contém uma chave com escopo WRITE.

Como as peças se encaixam

Há dois tipos de credenciais, e escolher a correta é essencial:

  • Chave de API (glk_live_…) — identifica seu backend. Ela pode ler e alterar os dados de todos os membros, por isso deve ficar somente no servidor. Use-a nas operações entre servidores e para gerar tokens de cliente.
  • Token de cliente — uma credencial de curta duração vinculada a um único cliente. O backend gera o token com a chave de API e o entrega a um cliente (navegador ou app). Esse cliente só pode consultar os dados e agir em nome daquela pessoa, então o token pode ser enviado ao dispositivo com segurança.

Escolha o padrão de integração

Você está criando…UseIr para
Um processo interno, uma sincronização com ERP ou um backend headlessChave de API diretamenteDo seu backend
Um app para celular ou de página única que mostra os pontos de um membroChave de API no servidor → token de cliente no dispositivoDentro de um app
Um PDV, marketplace ou checkout headless que deve conceder pontosChave de API, awardPointsForOrderDe outro canal

Função auxiliar para requisições

Todas as chamadas seguem a mesma estrutura, então encapsule-as em uma única função. Este exemplo em Node usa o fetch integrado (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;
}

Padrão 1 — Do seu backend (servidor a servidor)

Com uma chave WRITE, você pode agir em nome de qualquer membro da loja. Inscreva um cliente no programa de fidelidade, consulte os dados dele e conceda pontos:

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

Um valor negativo em awardPoints, assim como clawbackPoints, exige uma chave ADMIN. Mantenha esses fluxos em uma credencial separada e protegida.

Padrão 2 — Em um app para celular ou web

Nunca coloque a chave de API em um app. Em vez disso, disponibilize um endpoint simples no seu servidor que gere um token de cliente para o usuário autenticado. Assim, o app poderá se comunicar diretamente com o Gibbond usando esse token.

De onde vem o GID do cliente?

Um token de cliente fica vinculado ao GID informado em mintCustomerToken — por isso, é sua responsabilidade gerá-lo para o cliente correto. O Gibbond autentica seu backend por meio da chave de API, mas não autentica o comprador final. Antes de gerar o token, o servidor já precisa saber e confiar em qual cliente Shopify está autenticado. Há três formas de confirmar isso, em ordem de preferência:

Como o app autentica o clienteDe onde vem o GID
Shopify Customer Account API (recomendada)Autentique o cliente usando a Customer Account API da Shopify, baseada em OAuth. O backend troca o token recebido pelo cliente verificado e lê o GID. A Shopify assina a identidade de ponta a ponta.
Uma interface nativa do ShopifySe a experiência acontece dentro do Shopify (em um app embed de tema ou extensão de interface da conta do cliente), o Shopify já fornece a identidade assinada: logged_in_customer_id do app proxy ou sub do token de sessão da conta do cliente. Leia o valor no servidor e use-o como GID.
Seu próprio loginUm canal com contas próprias (um app personalizado ou PDV) associa o usuário a um GID de cliente do Shopify usando um mapeamento salvo quando o cliente foi criado. Você garante essa relação, então proteja esse fluxo com cuidado.
✅

Recomendação: Customer Account API. Em uma loja headless ou app para celular, autentique os clientes com a Customer Account API da Shopify e obtenha o GID a partir do token verificado pela Shopify. Assim, toda a cadeia — cliente → identidade verificada pela Shopify → backend → token de cliente — é confiável desde o início, sem precisar proteger um mapeamento de GID. O middleware requireAuth abaixo é exatamente onde essa verificação deve ser feita.

ℹ️

Se a sua interface já funciona dentro de uma sessão do Shopify (bloco de tema, checkout ou conta do cliente), normalmente você não precisa desta API: os blocos de app da loja e a integração da conta do cliente verificam a identidade do Shopify por você. Use tokens de cliente quando estiver fora desse contexto.

No seu servidor

Seu sistema de autenticação identifica qual cliente do Shopify está conectado (pelo GID). Gere um token para essa pessoa:

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

No app

Busque um token no servidor e chame o Gibbond diretamente. A consulta me retorna o cliente associado ao token, então não é necessário informar um ID:

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

Resgatar pelo app

Com um token de cliente, é possível resgatar uma recompensa para si mesmo, sem uma chave do lojista no dispositivo. A mutação retorna um código de desconto de uso único para aplicar no checkout:

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

Por padrão, os tokens duram 15 minutos (defina ttlSeconds em até 24h). Quando uma chamada retorna UNAUTHENTICATED, chame /loyalty/session novamente para gerar um novo token e tente de novo.

Padrão 3 — Conceder pontos em outro canal de venda

Quando um pedido acontecer fora do checkout do Shopify — em um PDV, marketplace ou loja headless — registre-o com awardPointsForOrder. O Gibbond aplica o multiplicador de nível, os boosts ativos e os marcos como faria em um pedido nativo. orderId torna seguro tentar novamente:

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

Cada item pode incluir productId e collectionIds opcionais, além de um lineTotal obrigatório. Assim, boosts e exclusões por produto e coleção também se aplicam aos pedidos do Shopify. Para confirmar os pontos depois (por exemplo, após o processamento do pedido), chame confirmPoints(customerId, orderId); para estorná-los em caso de reembolso, chame clawbackPoints com uma chave ADMIN.

Erros, novas tentativas e idempotência

  • Códigos. As falhas são retornadas em um array GraphQL errors; consulte errors[0].extensions.code: UNAUTHENTICATED (401), FORBIDDEN (403, escopo incorreto), RATE_LIMITED (429), BAD_USER_INPUT (400), NOT_FOUND (404).
  • Limites de requisições. 600 requisições por minuto por credencial. Em caso de 429, aguarde os segundos indicados no cabeçalho Retry-After e tente novamente.
  • Idempotência. Envie uma idempotencyKey para awardPoints e um orderId estável para awardPointsForOrder. Reenviar a mesma chave ou pedido não duplica os pontos, então você pode tentar novamente em caso de falha de rede.
  • Expiração do token. Se receber UNAUTHENTICATED em um token de cliente, gere outro e tente novamente.

Lista de verificação de segurança

  • Mantenha as chaves de API somente em segredos no servidor — nunca em pacotes do app, código do navegador ou controle de versão.
  • Use um token de cliente para tudo que é executado em um dispositivo; nunca use uma chave de API.
  • Conceda a cada integração o menor escopo necessário (uma chave READ para painéis, WRITE para acumular/resgatar pontos e ADMIN somente para reembolsos/correções).
  • Se houver suspeita de vazamento, troque a chave imediatamente pelo admin — a revogação tem efeito instantâneo.
  • Gere tokens de cliente com o menor valor prático de ttlSeconds.

Para ver a lista completa de tipos, consultas, mutações e campos, consulte a referência da API.