Integración de la API
Guía práctica para integrar la API GraphQL de Gibbond, con ejemplos listos para copiar y pegar en un servicio interno, una app móvil o web, u otro canal de venta. Consulta la referencia de la API para ver el esquema completo.
En esta página
Plan Pro. Crea una clave de API en la página Claves de API del panel de Gibbond y guárdala en una variable de entorno del servidor. En los ejemplos siguientes se supone que GIBBOND_API_KEY contiene una clave con permiso WRITE.
Cómo encajan las piezas
Hay dos credenciales; elegir la adecuada es fundamental:
- Clave de API (
glk_live_…) — identifica tu backend. Puede leer y modificar los datos de todos los miembros, por lo que solo debe guardarse en tu servidor. Úsala para las operaciones entre servidores y para crear tokens de cliente. - Token de cliente — una credencial de corta duración asociada a un solo cliente. Tu backend lo genera con la clave de API y se lo entrega a un cliente (navegador o app). Este solo puede consultar los datos de esa persona y actuar en su nombre, así que el token puede enviarse al dispositivo de forma segura.
Elige el patrón adecuado
| Estás creando… | Usa | Ir a |
|---|---|---|
| Un proceso interno, una sincronización con un ERP o un backend headless | Clave de API directamente | Desde tu backend |
| Una app móvil o de una sola página que muestra los puntos de un miembro | Clave de API en tu servidor → token de cliente en el dispositivo | Dentro de una app |
| Un POS, marketplace o checkout headless que debe asignar puntos | Clave de API, awardPointsForOrder | Desde otro canal |
Función auxiliar para solicitudes
Todas las llamadas tienen la misma estructura, así que puedes encapsularla una sola vez. Este ejemplo de Node usa fetch, que viene 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;
} Patrón 1 — Desde tu backend (servidor a servidor)
Con una clave WRITE puedes realizar acciones para cualquier miembro de tu tienda. Inscribe a un cliente en el programa de fidelización, consulta sus datos y asígnale puntos:
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,
); Un valor negativo en awardPoints, así como clawbackPoints, requieren una clave ADMIN. Mantén esos procesos en una credencial separada y bien protegida.
Patrón 2 — En una app móvil o web
No incluyas nunca la clave de API en una app. En su lugar, crea un endpoint pequeño en tu servidor que genere un token de cliente para el usuario con sesión iniciada y permite que la app se comunique directamente con Gibbond usando ese token.
¿De dónde sale el GID del cliente?
Un token de cliente queda vinculado al GID que pasas a mintCustomerToken, así que debes asegurarte de generarlo para el cliente correcto. Gibbond autentica tu backend mediante la clave de API, pero no autentica al comprador final. Antes de generar el token, tu servidor debe saber y poder verificar qué cliente de Shopify ha iniciado sesión. Hay tres formas de establecerlo, por orden de preferencia:
| Cómo autentica tu app al comprador | De dónde sale el GID |
|---|---|
| Shopify Customer Account API (recomendada) | Inicia la sesión del comprador con la Customer Account API de Shopify, basada en OAuth. Tu backend intercambia el token resultante para obtener el cliente verificado y leer su GID. Shopify firma la identidad de extremo a extremo. |
| Una interfaz nativa de Shopify | Si la experiencia se ejecuta dentro de Shopify (mediante una inserción de app en el tema o una extensión de interfaz de cuenta de cliente), Shopify ya proporciona la identidad firmada: logged_in_customer_id del app proxy o sub del token de sesión de la cuenta de cliente. Lee el valor en el servidor y usa ese GID. |
| Tu propio inicio de sesión | Un canal con cuentas propias (una app personalizada o un POS) vincula al usuario con el GID de un cliente de Shopify mediante una correspondencia guardada al crear el cliente. Tú respondes de esa relación, así que protégela con cuidado. |
Recomendado: Customer Account API. Para una tienda headless o una app móvil, autentica a los compradores con la Customer Account API de Shopify y obtén el GID a partir del token verificado por Shopify. Así, toda la cadena —comprador → identidad verificada por Shopify → backend → token de cliente— es fiable desde el diseño, sin que tengas que proteger una correspondencia de GID. El middleware requireAuth que aparece a continuación es el lugar adecuado para hacer esta comprobación.
Si tu interfaz ya funciona dentro de una sesión de Shopify (bloque de tema, checkout o cuenta de cliente), normalmente no necesitas esta API: los bloques de app de la tienda y la integración de cuenta de cliente verifican tu identidad de Shopify. Recurre a los tokens de cliente cuando estés fuera de ese contexto.
En tu servidor
Tu propio sistema de autenticación indica qué cliente de Shopify ha iniciado sesión (su GID). Genera un token para ese 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,
});
}); En la app
Obtén un token de tu servidor y llama directamente a Gibbond. La consulta me devuelve el cliente asociado al token, así que no hace falta indicar un 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); Canjear desde la app
Con un token de cliente se puede canjear una recompensa para uno mismo, sin una clave de comerciante en el dispositivo. La mutación devuelve un código de descuento de un solo uso que se aplica en el 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); Los tokens duran 15 minutos de forma predeterminada (configura ttlSeconds hasta 24h). Si una llamada devuelve UNAUTHENTICATED, vuelve a llamar a /loyalty/session para obtener un token nuevo y vuelve a intentarlo.
Patrón 3 — Asignar puntos desde otro canal de venta
Cuando un pedido se realice fuera del checkout de Shopify —en un POS, marketplace o tienda headless—, regístralo con awardPointsForOrder. Gibbond aplica el multiplicador de nivel, los boosts activos y los hitos igual que en un pedido nativo. orderId evita duplicar puntos al volver a intentarlo:
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 artículo puede incluir productId y collectionIds opcionales, además de un lineTotal obligatorio. Así, los boosts y las exclusiones por producto y colección se aplican igual que en los pedidos de Shopify. Para confirmar los puntos más adelante, por ejemplo, tras preparar el pedido, llama a confirmPoints(customerId, orderId); para revertirlos en un reembolso, llama a clawbackPoints con una clave ADMIN.
Errores, reintentos e idempotencia
- Códigos. Los errores se devuelven en un array de GraphQL
errors; consultaerrors[0].extensions.code:UNAUTHENTICATED(401),FORBIDDEN(403, permiso incorrecto),RATE_LIMITED(429),BAD_USER_INPUT(400),NOT_FOUND(404). - Límites de solicitudes. 600 solicitudes por minuto y credencial. Si recibes
429, espera los segundos indicados en el encabezadoRetry-Aftery vuelve a intentarlo. - Idempotencia. Envía una
idempotencyKeyaawardPointsy unorderIdestable aawardPointsForOrder. Reenviar la misma clave o el mismo pedido no vuelve a asignar los puntos, así que puedes repetir la solicitud si falla la red. - Caducidad del token. Si recibes
UNAUTHENTICATEDcon un token de cliente, genera otro y vuelve a intentarlo.
Lista de comprobación de seguridad
- Guarda las claves de API únicamente en secretos del servidor; nunca en los paquetes de la app, el código del navegador ni el control de versiones.
- Usa un token de cliente para cualquier función que se ejecute en un dispositivo; nunca una clave de API.
- Asigna a cada integración el permiso mínimo que necesita (una clave
READpara los paneles,WRITEpara acumular/canjear puntos yADMINsolo para reembolsos/correcciones). - Si sospechas que una clave se ha filtrado, renuévala de inmediato desde el panel; la revocación surte efecto al instante.
- Genera tokens de cliente con el valor mínimo práctico de
ttlSeconds.
Para ver la lista completa de tipos, consultas, mutaciones y campos, consulta la referencia de la API.