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 móveis ou web e outros canais de venda. Consulta a referência da API para veres o esquema completo.
Nesta página
Plano Pro. Cria uma chave de API na página Chaves API do admin do Gibbond e guarda-a numa variável de ambiente do servidor. Os exemplos seguintes pressupõem que GIBBOND_API_KEY contém uma chave com âmbito WRITE.
Como as peças se encaixam
Existem dois tipos de credenciais; escolher a certa é essencial:
- Chave de API (
glk_live_…) — identifica o teu backend. Pode ler e alterar os dados de todos os membros, por isso deve ficar apenas no servidor. Usa-a nas operações entre servidores e para criar tokens de cliente. - Token de cliente — uma credencial de curta duração associada a um único cliente. O teu backend gera-o com a chave de API e entrega-o a um cliente (navegador ou app). Este só pode consultar os dados e agir em nome dessa pessoa, por isso o token pode ser enviado para o dispositivo em segurança.
Escolhe o padrão de integração
| Estás a criar… | Usa | Ir para |
|---|---|---|
| Um processo interno, uma sincronização com ERP ou um backend headless | Chave de API diretamente | Do teu backend |
| Uma app móvel ou de página única que mostra os pontos de um membro | Chave de API no teu servidor → token de cliente no dispositivo | Numa app |
| Um POS, marketplace ou checkout headless que deve atribuir pontos | Chave de API, awardPointsForOrder | De outro canal |
Função auxiliar para pedidos
Todas as chamadas seguem a mesma estrutura, por isso encapsula-as numa função. Este exemplo de 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 teu backend (servidor a servidor)
Com uma chave WRITE, podes agir em nome de qualquer membro da tua loja. Inscreve um cliente, consulta os dados e atribui-lhe 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, requer uma chave ADMIN. Mantém esses processos numa credencial separada e bem protegida.
Padrão 2 — Numa app móvel ou web
Nunca coloques a chave de API numa app. Em vez disso, disponibiliza um endpoint simples no teu servidor que gere um token de cliente para o utilizador autenticado. Assim, a app pode comunicar diretamente com o Gibbond através desse token.
De onde vem o GID do cliente?
Um token de cliente fica associado ao GID indicado em mintCustomerToken — por isso, és responsável por o gerar para o cliente certo. O Gibbond autentica o teu backend através da chave de API, mas não autentica o cliente final. Antes de gerar o token, o teu servidor já tem de saber e confirmar que cliente Shopify iniciou sessão. Existem três formas de o determinar, por ordem de preferência:
| Como a app autentica o cliente | Origem do GID |
|---|---|
| Shopify Customer Account API (recomendada) | Autentica o cliente através da Customer Account API da Shopify, baseada em OAuth. O teu backend troca o token obtido pela identidade do cliente verificado e lê o GID. A Shopify assina a identidade de ponta a ponta. |
| Uma interface nativa da Shopify | Se a experiência decorrer dentro da Shopify (através de um app embed do tema ou de uma extensão da interface da conta de cliente), a Shopify já fornece a identidade assinada: logged_in_customer_id do app proxy ou sub do token de sessão da conta de cliente. Lê esse valor no servidor e usa-o como GID. |
| O teu próprio início de sessão | Um canal com contas próprias (uma app personalizada ou um POS) associa o utilizador ao GID de um cliente Shopify através de um mapeamento guardado quando o cliente foi criado. És responsável por essa ligação, por isso protege-a cuidadosamente. |
Recomendação: Customer Account API. Numa loja headless ou app móvel, autentica os clientes através da Customer Account API da Shopify e obtém o GID a partir do token verificado pela Shopify. Assim, toda a cadeia — cliente → identidade verificada pela Shopify → backend → token de cliente — é fiável desde a origem, sem precisares de proteger um mapeamento de GID. O middleware requireAuth abaixo é o local certo para fazer esta verificação.
Se a tua interface já funciona dentro de uma sessão Shopify (bloco do tema, checkout ou conta de cliente), normalmente não precisas desta API: os blocos de app da loja e a integração da conta de cliente verificam a identidade Shopify por ti. Usa tokens de cliente quando estiveres fora desse contexto.
No teu servidor
O teu sistema de autenticação indica que cliente Shopify tem sessão iniciada (através do GID). Gera um token para esse cliente:
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,
});
}); Na app
Obtém um token do teu servidor e chama diretamente o Gibbond. A consulta me devolve o cliente associado ao token, pelo que não é necessário indicar 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 na app
Com um token de cliente, é possível resgatar uma recompensa para si próprio, sem uma chave do comerciante no dispositivo. A mutação devolve um código de desconto de utilização única 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 predefinição, os tokens duram 15 minutos (define ttlSeconds até 24h). Quando uma chamada devolve UNAUTHENTICATED, volta a chamar /loyalty/session para obter um novo token e tenta novamente.
Padrão 3 — Atribuir pontos noutro canal de venda
Quando uma encomenda for feita fora do checkout da Shopify — num POS, marketplace ou loja headless — regista-a com awardPointsForOrder. O Gibbond aplica o multiplicador de nível, os boosts ativos e os marcos tal como numa encomenda nativa. orderId torna seguro voltar a tentar:
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 linha pode incluir productId e collectionIds opcionais, bem como um lineTotal obrigatório. Assim, boosts e exclusões por produto e coleção também se aplicam às encomendas Shopify. Para confirmar os pontos mais tarde (por exemplo, após o processamento da encomenda), chama confirmPoints(customerId, orderId); para os reverter em caso de reembolso, chama clawbackPoints com uma chave ADMIN.
Erros, novas tentativas e idempotência
- Códigos. Os erros são devolvidos num array GraphQL
errors; consultaerrors[0].extensions.code:UNAUTHENTICATED(401),FORBIDDEN(403, âmbito incorreto),RATE_LIMITED(429),BAD_USER_INPUT(400),NOT_FOUND(404). - Limites de pedidos. 600 pedidos por minuto por credencial. Se receberes
429, aguarda os segundos indicados no cabeçalhoRetry-Aftere volta a tentar. - Idempotência. Passa uma
idempotencyKeyaawardPointse umorderIdestável aawardPointsForOrder. Reenviar a mesma chave ou encomenda não atribui os pontos uma segunda vez, pelo que podes voltar a tentar em caso de falha de rede. - Expiração do token. Se receberes
UNAUTHENTICATEDcom um token de cliente, cria outro e volta a tentar.
Lista de verificação de segurança
- Guarda as chaves de API apenas em segredos do servidor — nunca em bundles da app, código do navegador ou controlo de versões.
- Usa um token de cliente para tudo o que é executado num dispositivo; nunca uses uma chave de API.
- Atribui a cada integração o âmbito mínimo necessário (uma chave
READpara dashboards,WRITEpara acumular/resgatar pontos eADMINapenas para reembolsos/correções). - Se uma chave puder ter sido exposta, troca-a de imediato no admin — a revogação é imediata.
- Cria tokens de cliente com o valor mais curto possível de
ttlSeconds.
Para veres a lista completa de tipos, consultas, mutações e campos, consulta a referência da API.