API GreenGo Checkout
Conecte seu ERP, site ou automação à sua loja: sincronize produtos, acompanhe pedidos e receba eventos em tempo real. Todos os valores são em centavos inteiros (13500 = R$ 135,00).
Autenticação
Gere uma chave em Painel → Integrações → Chaves de API. Envie em todas as chamadas, somente a partir do seu servidor:
curl https://SEU-DOMINIO/api/v1/store \
-H "X-API-Key: gg_live_..."
Também aceitamos Authorization: Bearer gg_live_.... A chave dá acesso somente à loja em que foi criada. Revogue a qualquer momento no painel.
Erros e limites
Erros sempre têm o mesmo formato. details aparece quando há campos inválidos.
{ "error": "INVALID_PRODUCT", "message": "Revise os dados do produto.", "details": { "price": "Preco em centavos inteiros e nao negativo." } }
| HTTP | Quando |
|---|---|
| 401 | Chave ausente, inválida ou revogada |
| 404 | Recurso não existe nesta loja |
| 409 | Transição de status inválida ou Idempotency-Key reutilizada com outro corpo |
| 422 | Dados inválidos (veja details) |
| 207 | Lote processado com alguns itens com erro (veja results) |
| 429 | Mais de 120 requisições por minuto por chave. Respeite o cabeçalho Retry-After |
Idempotência
Em POST /store/orders e POST /store/products, envie Idempotency-Key com um valor único por operação. Se a rede cair e você repetir a chamada, devolvemos a mesma resposta sem criar duplicado (cabeçalho Idempotent-Replayed: true). A chave vale por 24 horas.
Produtos
/api/v1/store/products?limit=50&offset=0&sku=&updated_since=/api/v1/store/products/{id}/api/v1/store/products/api/v1/store/products/{id}/api/v1/store/products/{id}Produto com variações (cor, tamanho). Até 3 opções e 250 variações. Cada variação tem preço, estoque, SKU e foto próprios.
{
"name": "Camiseta Linho",
"price": 8990,
"compareAt": 11990,
"weightGrams": 350, "heightCm": 4, "widthCm": 25, "lengthCm": 30,
"images": ["https://cdn.sualoja.com/camiseta.jpg"],
"options": [{ "name": "Cor", "values": ["Areia", "Preto"] }, { "name": "Tamanho", "values": ["P", "M"] }],
"variants": [
{ "sku": "CL-AR-P", "options": { "Cor": "Areia", "Tamanho": "P" }, "price": 8990, "stock": 4 },
{ "sku": "CL-PR-M", "options": { "Cor": "Preto", "Tamanho": "M" }, "price": 9490, "stock": 0, "image": "https://cdn.sualoja.com/preto.jpg", "weightGrams": 420 }
]
}
No PATCH, enviar variants substitui a lista inteira. Para mudar só estoque, use /store/inventory.
Peso e medidas para o frete (opcionais, do produto já embalado): weightGrams em gramas inteiros (1 a 100.000) e heightCm, widthCm, lengthCm em centímetros inteiros (1 a 300). Na variação, cada campo é opcional: vazio herda o valor do produto. Envie null para apagar um valor; campo ausente mantém o que já estava gravado (também nas variações ao reenviar variants). As cotações do Melhor Envio e da Frenet usam esses valores por item do carrinho; o que faltar vem do pacote padrão da conexão. A resposta traz shippingReady: true quando o produto (ou todas as variações) tem peso e as 3 medidas.
Sincronizar pelo ID do seu sistema
/api/v1/store/products/external/{seuId}Cria o produto se o ID ainda não existe na GreenGo, ou atualiza se já existe. Resposta 201 (criado) ou 200 (atualizado). É o jeito mais simples de manter o catálogo espelhado.
Lote de produtos
/api/v1/store/products/batchAté 100 produtos por chamada, cada um com externalId. Um item inválido não impede os outros.
{ "products": [ { "externalId": "erp-10", "name": "Garrafa", "price": 5000, "stock": 2 }, { "externalId": "erp-11", "stock": 9 } ] }
→ { "created": 1, "updated": 1, "failed": 0, "results": [ { "index": 0, "ok": true, "created": true, "id": "prd_..." }, ... ] }
Estoque em massa
/api/v1/store/inventoryAté 500 itens, identificados por sku, variantId ou productId.
{ "items": [ { "sku": "CL-AR-P", "stock": 12 }, { "variantId": "var_...", "stock": 0 } ] }
Pedidos
/api/v1/store/orders?status=paid&from=2026-09-01&to=2026-09-30&q=&limit=50&offset=0/api/v1/store/orders/{id}/api/v1/store/ordersO total é sempre calculado pela GreenGo a partir do catálogo. CPF/CNPJ é validado e o telefone é normalizado para o formato internacional (5511999998888).
{
"customer": { "name": "Ana Silva", "email": "ana@exemplo.com", "phone": "(11) 99999-8888", "document": "529.982.247-25" },
"items": [ { "productId": "prd_...", "variantId": "var_...", "quantity": 2 } ],
"paymentMethod": "pix",
"address": { "cep": "01310-100", "street": "Avenida Paulista", "number": "1000", "complement": "", "district": "Bela Vista", "city": "São Paulo", "uf": "SP" },
"shippingOptionId": "pac",
"couponCode": "VOLTA10",
"orderBump": false
}
Lojas com entrega (padrão) exigem address e shippingOptionId; lojas de produto digital desligam isso no painel. O pedido devolve a composição do total: subtotal, discount (cupom), pixDiscount, shipping, total. Cupom inválido responde 422 com o motivo (expirado, limite de usos, compra mínima). Para mostrar o total antes de criar o pedido, use POST /api/v1/checkout/quote com os mesmos campos (uf no lugar de address).
Mudar status (gateway, ERP)
/api/v1/store/orders/{id}/status{ "status": "paid", "reference": "id-da-transacao-no-gateway" }
| De | Para |
|---|---|
| pending | paid, failed, canceled |
| failed | paid, canceled |
| paid | refunded |
Ao virar paid, o estoque é baixado. Em refunded, devolvido. O cliente é avisado por WhatsApp e e-mail quando esses canais estão configurados.
Checkout pelo seu site (itens com preço)
Para quem monta o carrinho no próprio site: kit com desconto, segunda peça mais barata, gravação, personalização. Seu servidor manda os itens já com preço e recebe o link do checkout transparente, aberto direto no pagamento, no seu domínio próprio quando ele está no ar. Os itens ficam travados: o navegador do comprador não muda preço nem quantidade.
/api/v1/store/checkout-sessionscurl -X POST https://SEU-DOMINIO/api/v1/store/checkout-sessions -H "X-API-Key: gg_live_..." -H "Content-Type: application/json" -d '{
"items": [
{ "name": "Faca Sentinela", "unitPrice": 13500, "quantity": 1, "note": "Gravar: João", "image": "https://seusite.com/sentinela.jpg", "sku": "sentinela" },
{ "name": "Faca Raiz", "unitPrice": 6075, "quantity": 1, "note": "Peça adicional, 55% off", "sku": "raiz" }
],
"returnUrl": "https://seusite.com/faca/sentinela",
"utm": { "utm_source": "meta", "fbclid": "..." }
}'
201 { "session": { "id": "cart_...", "url": "https://checkout.seusite.com/ui_kits/checkout/?store=...&cart=...", "subtotal": 19575, "expiresAt": "..." } }
| Campo | Regra |
|---|---|
unitPrice | Centavos inteiros (R$ 135,00 = 13500). Calcule no seu servidor, nunca no navegador. |
note | Observação da linha (gravação, variação, "peça adicional"). Aparece no pedido, no e-mail e no painel. Até 200 caracteres. |
image | Opcional, só https. |
returnUrl | Opcional, https. Para onde o botão "Voltar para a loja" leva. |
expiresInHours | Opcional, de 1 a 168. Padrão 48. Link vencido responde 410 SESSION_EXPIRED e não cobra. |
Redirecione o comprador para session.url. Frete, cupom, desconto no Pix e forma de pagamento seguem as regras da loja no painel. Até 50 itens por sessão.
Webhooks de saída
Cadastre em Painel → Integrações ou pela API. Enviamos um POST JSON para sua URL a cada evento escolhido:
POST https://seusistema.com/webhooks/greengo
GreenGo-Event-Id: evt_...
GreenGo-Event-Type: order.paid
GreenGo-Signature: t=1790000000,v1=5f2c...
{ "id": "evt_...", "type": "order.paid", "createdAt": "2026-09-23T14:02:11.000Z", "storeCode": "MINHA-LOJA-7K2Q", "data": { "order": { ... } } }
- Responda com qualquer 2xx em até 10 segundos. Processe depois, se for demorado.
- Se falhar, tentamos de novo após 1 min, 5 min, 30 min, 2 h, 6 h, 12 h e 24 h.
- Depois de 15 falhas seguidas o webhook é pausado. Reative no painel.
- Reenvios mantêm o mesmo
GreenGo-Event-Id: use-o para ignorar duplicados. - Em produção, só aceitamos URLs
httpspúblicas.
/api/v1/store/webhooks/api/v1/store/webhooks { "url", "events": ["order.paid"], "description" }/api/v1/store/webhooks/{id}/api/v1/store/webhooks/{id}/api/v1/store/webhooks/{id}/deliveriesValidar a assinatura
Calcule HMAC-SHA256(segredo, t + "." + corpo_bruto) e compare com v1. Recuse eventos com t mais antigo que 5 minutos.
// Node.js (Express com express.raw())
const crypto = require("crypto");
function valido(req, segredo) {
const partes = Object.fromEntries(req.get("GreenGo-Signature").split(",").map((p) => p.split("=")));
const esperado = crypto.createHmac("sha256", segredo).update(partes.t + "." + req.body.toString("utf8")).digest("hex");
const recente = Math.abs(Date.now() / 1000 - Number(partes.t)) < 300;
return recente && crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(partes.v1));
}
// PHP
$corpo = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_GREENGO_SIGNATURE']), $p);
$esperado = hash_hmac('sha256', $p['t'] . '.' . $corpo, $segredo);
$valido = hash_equals($esperado, $p['v1']) && abs(time() - (int)$p['t']) < 300;
Tipos de evento
| Evento | Quando | data |
|---|---|---|
| order.created | Pedido criado no checkout ou pela API | order |
| order.paid | Pagamento confirmado | order |
| order.failed | Pagamento recusado | order |
| order.canceled | Pedido cancelado | order |
| order.refunded | Pedido estornado por inteiro | order, refund (id, amount, reason, totalRefunded, full) |
| order.partially_refunded | Estorno parcial (um evento por estorno) | order, refund |
| order.chargeback | Chargeback aberto: pagamento em disputa | order, dispute (status, amount) |
| order.chargeback_won | Chargeback ganho: a venda volta a valer | order, dispute |
| order.chargeback_lost | Chargeback perdido: valor devolvido ao comprador | order, dispute |
| order.invoice_issued | Nota fiscal do pedido autorizada no emissor (eNotas ou Notazz), com número e links do PDF/XML | order, invoice |
| product.created / updated / deleted | Mudança no catálogo | product |
| cart.abandoned | Comprador deixou dados e não finalizou | cart |
| cart.recovered | Carrinho abandonado virou pedido | cart, order |
| import.finished | Importação de catálogo terminou | import |
| ping | Botão "Enviar teste" do painel | message |
Webhooks de entrada
Para sua plataforma ou gateway avisar a GreenGo, crie uma conexão em Painel → Integrações → Receber eventos. Você recebe uma URL e um segredo. Envie:
POST /api/v1/webhooks/{idDaConexao}
X-Event-Id: id-unico-do-evento
X-Webhook-Signature: sha256=HMAC_SHA256(segredo, corpo_bruto)
{ "type": "order.updated", "order": { "id": "GG-AB12CD34", "status": "paid", "reference": "pay_123" } }
{ "type": "product.updated", "product": { "externalId": "erp-10", "price": 5500, "stock": 3 } }
Eventos repetidos com o mesmo X-Event-Id são ignorados. Um evento que falhou (por exemplo, transição inválida) não é marcado como processado e pode ser reenviado.