Visão geral
A API de integração permite que sistemas externos (loja virtual, marketplace, ERP, automações) enviem dados ao Forge. Todas as rotas usam a mesma chave de API da empresa e o mesmo formato de resposta.
- Endereço base
https://forge.carvalhosilvatech.com.br- Formato
- JSON (
Content-Type: application/json), propriedades emcamelCase - Autenticação
- Chave de API da empresa (
fgk_...) - Limite
- 120 requisições por minuto por endereço IP
| Rota | Para que serve |
|---|---|
POST /api/integracoes/vendas | Enviar uma venda já paga. Ela vai para a conferência no Forge e só vira pedido depois da confirmação. |
POST /api/integracoes/contatos | Criar ou atualizar um lead com tags e dados, para disparar campanhas. |
POST /api/integracoes/contatos/remover-tags | Tirar o lead de um fluxo (por exemplo, quando ele comprou). |
POST /api/integracoes/notificacoes | Enviar uma mensagem de WhatsApp ao cliente, pelo número conectado da empresa. |
Começando
1. Crie a chave de API
Um Administrador da empresa cria a chave no Forge, em WhatsApp → Avisos aos clientes → Integração com outras ferramentas → Nova chave.
- A chave é exibida uma única vez. Guarde em uma variável de ambiente ou cofre de segredos.
- Cada empresa pode ter até 5 chaves ativas. Use uma chave por aplicação, para revogar uma sem afetar as outras.
- A chave pode ser revogada a qualquer momento, e a revogação vale na hora.
A empresa é sempre a dona da chave. Não existe campo de empresa no corpo das requisições.
2. Autentique cada chamada
Envie a chave em um dos cabeçalhos:
X-Api-Key: fgk_sua_chaveAuthorization: Bearer fgk_sua_chaveFaça as chamadas somente do servidor da sua aplicação. Nunca coloque a chave em JavaScript de navegador, aplicativo móvel ou repositório, e não a registre em logs.
3. Faça a primeira chamada
curl -X POST https://forge.carvalhosilvatech.com.br/api/integracoes/vendas \
-H "X-Api-Key: $FORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"origem": "loja-virtual",
"idExterno": "PED-1234",
"cliente": { "nome": "Maria Silva", "email": "[email protected]" },
"itens": [{ "sku": "GAT-01", "quantidade": 1, "precoUnitario": 50.00 }],
"pagamento": { "forma": "pix" }
}'Resposta esperada: 202 Accepted. A venda aparece em Vendas → Vendas recebidas.
Convenções e erros
Todas as respostas JSON usam o mesmo envelope:
{
"success": true,
"message": "Texto legível para humanos.",
"error": null,
"timestamp": "2026-11-04T12:00:00Z",
"data": { }
}Em caso de falha, success é false e message explica o motivo.
| Status | Significado | O que fazer |
|---|---|---|
200 / 202 | Recebido e processado (ou na fila). | Nada. Guarde o id retornado para conciliação. |
400 | Dado inválido; message diz qual. | Corrija o dado. Não repita a mesma requisição. |
401 | Chave ausente, inválida ou revogada. | Não repita. Confira a chave e avise a equipe. |
429 | Limite excedido (por minuto ou por dia, conforme a rota). Pode vir sem corpo JSON. | Aguarde e tente de novo, com espera crescente. |
5xx | Erro inesperado no Forge. | Tente de novo com espera crescente. |
Idempotência
Redes falham e a sua aplicação pode não saber se uma chamada chegou. Por isso cada rota tem uma chave de repetição: origem + idExterno nas vendas, o e-mail nos leads e referencia nos avisos. Repetir a mesma chamada é seguro e não duplica nada.
Estratégia de repetição recomendada
- Defina um timeout de 10 a 15 segundos.
- Repita apenas timeout,
429e5xx, com espera crescente (por exemplo 1 s, 5 s, 30 s, 2 min, 10 min) e no máximo 5 tentativas. - Chame o Forge fora do caminho crítico do seu checkout (fila ou job em segundo plano). Uma falha do Forge nunca deve impedir uma venda sua.
Vendas
POST /api/integracoes/vendas
Envia ao Forge uma venda já paga. A venda não vira pedido sozinha: ela cai na caixa de entrada (Vendas → Vendas recebidas), onde a equipe confere os dados, vincula cliente e produtos, escolhe canal, taxas e embalagem e confirma. Só então vira um pedido de venda comum, com baixa de estoque e produção como qualquer outro.
Fluxo
- Sua aplicação envia a venda. O Forge responde
202e a coloca como pendente. - O Forge sugere vínculos: o cliente (por CPF/CNPJ e, na falta, por e-mail) e o produto de cada item (por vínculo já confirmado e, na falta, por SKU igual). Nada é criado sozinho.
- A equipe confirma no Forge. O pedido nasce como pago. O vínculo do SKU com o produto fica salvo para as próximas vendas.
Corpo da requisição
{
"origem": "loja-virtual",
"idExterno": "PED-1234",
"dataVenda": "2026-11-03T10:00:00Z",
"cliente": {
"nome": "Maria Silva",
"cpfCnpj": "123.456.789-09",
"email": "[email protected]",
"telefone": "11999998888",
"endereco": {
"cep": "01001000",
"logradouro": "Praça da Sé",
"numero": "100",
"complemento": "Ap 4",
"bairro": "Sé",
"cidade": "São Paulo",
"estado": "SP"
}
},
"itens": [
{ "sku": "GAT-01", "descricao": "Gatinha articulada", "quantidade": 2, "precoUnitario": 50.00 }
],
"frete": 20.00,
"desconto": 10.00,
"pagamento": { "forma": "pix" },
"observacoes": "Presente"
}| Campo | Tipo | Obrigatório | Regras |
|---|---|---|---|
origem | texto | Sim | Nome da sua aplicação, texto livre, até 50 caracteres. Guardado em minúsculas. |
idExterno | texto | Sim | Número do pedido na sua aplicação, até 100 caracteres. Junto com origem, identifica a venda e evita duplicidade. |
dataVenda | data ISO 8601 | Não | Em UTC (ex.: 2026-11-03T10:00:00Z). Vazia = momento do recebimento. |
cliente.nome | texto | Sim | Até 200 caracteres. |
cliente.cpfCnpj | texto | Não | Qualquer formatação. Ajuda a reconhecer um cliente já cadastrado. |
cliente.email | texto | Não | Na falta de documento, ajuda a reconhecer o cliente. |
cliente.telefone | texto | Não | Com DDD. Até 20 caracteres. |
cliente.endereco | objeto | Não | cep, logradouro, numero, complemento, bairro, cidade e estado (sigla de 2 letras). Usado ao cadastrar o cliente. |
itens | lista | Sim | Ao menos um item. |
itens[].sku | texto | Sim | Código do produto na sua aplicação, até 100 caracteres. Se for igual ao SKU de um produto do Forge, ele é sugerido. |
itens[].quantidade | inteiro | Sim | Maior que zero. |
itens[].precoUnitario | número | Sim | Preço unitário cobrado, zero ou mais. Use ponto como separador decimal. |
itens[].descricao | texto | Não | Mostrada na conferência. Vazia = o SKU. |
frete | número | Não | Frete cobrado do cliente. |
desconto | número | Não | Desconto total do pedido. |
pagamento.forma | texto | Sim | pix, cartao, dinheiro, boleto ou marketplace. |
observacoes | texto | Não | Até 2.000 caracteres. |
O total é calculado pelo Forge: soma(quantidade × precoUnitario) − desconto + frete. Toda venda enviada é tratada como paga: não envie vendas aguardando pagamento. Campos desconhecidos são ignorados.
Resposta
HTTP/1.1 202 Accepted
{
"success": true,
"message": "Venda recebida e aguardando conferência no Forge.",
"error": null,
"timestamp": "2026-11-04T12:00:00Z",
"data": { "id": "6f0e5a8c-0000-0000-0000-000000000000", "duplicada": false }
}data.id: identificador da venda recebida no Forge. Guarde para suporte e conciliação.data.duplicada:truequando o mesmoorigem+idExternojá havia sido recebido. Nada foi criado de novo, e os dados enviados agora são ignorados: vale o primeiro envio.
Erros desta rota
| Status | Quando |
|---|---|
400 | origem, idExterno ou cliente.nome ausentes; lista de itens vazia; SKU ausente; quantidade menor que 1; preço, frete ou desconto negativos; forma de pagamento desconhecida; campo acima do tamanho máximo. |
401 | Chave de API ausente, inválida ou revogada. |
429 | Mais de 500 vendas por 24 horas para a empresa, ou mais de 120 requisições por minuto do mesmo IP. |
Exemplos de código
// Node.js 18+
async function enviarVenda(pedido) {
const resposta = await fetch('https://forge.carvalhosilvatech.com.br/api/integracoes/vendas', {
method: 'POST',
headers: {
'X-Api-Key': process.env.FORGE_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
origem: 'loja-virtual',
idExterno: String(pedido.numero),
dataVenda: pedido.pagoEm.toISOString(),
cliente: {
nome: pedido.cliente.nome,
cpfCnpj: pedido.cliente.documento,
email: pedido.cliente.email,
telefone: pedido.cliente.telefone,
endereco: pedido.entrega,
},
itens: pedido.itens.map(i => ({
sku: i.sku,
descricao: i.nome,
quantidade: i.quantidade,
precoUnitario: i.preco,
})),
frete: pedido.frete,
desconto: pedido.desconto,
pagamento: { forma: 'pix' },
}),
signal: AbortSignal.timeout(15000),
});
if (resposta.status === 202) return resposta.json();
if (resposta.status === 429 || resposta.status >= 500) {
throw new Error(`Falha temporária (${resposta.status}). Repita com o mesmo idExterno.`);
}
const erro = await resposta.json().catch(() => ({}));
throw new Error(`Forge recusou a venda (${resposta.status}): ${erro.message ?? 'sem detalhes'}`);
}using System.Net;
using System.Net.Http.Json;
using var http = new HttpClient
{
BaseAddress = new Uri("https://forge.carvalhosilvatech.com.br"),
Timeout = TimeSpan.FromSeconds(15)
};
http.DefaultRequestHeaders.Add("X-Api-Key", Environment.GetEnvironmentVariable("FORGE_API_KEY"));
var resposta = await http.PostAsJsonAsync("/api/integracoes/vendas", new
{
origem = "loja-virtual",
idExterno = "PED-1234",
cliente = new { nome = "Maria Silva", email = "[email protected]" },
itens = new[] { new { sku = "GAT-01", quantidade = 2, precoUnitario = 50.00m } },
frete = 20.00m,
pagamento = new { forma = "pix" }
});
if (resposta.StatusCode != HttpStatusCode.Accepted)
throw new InvalidOperationException($"Forge recusou a venda: {(int)resposta.StatusCode}");import os
import requests
resposta = requests.post(
"https://forge.carvalhosilvatech.com.br/api/integracoes/vendas",
headers={"X-Api-Key": os.environ["FORGE_API_KEY"]},
json={
"origem": "loja-virtual",
"idExterno": "PED-1234",
"cliente": {"nome": "Maria Silva", "email": "[email protected]"},
"itens": [{"sku": "GAT-01", "quantidade": 2, "precoUnitario": 50.00}],
"frete": 20.00,
"pagamento": {"forma": "pix"},
},
timeout=15,
)
if resposta.status_code != 202:
raise RuntimeError(f"Forge recusou a venda: {resposta.status_code} {resposta.text}")curl -X POST https://forge.carvalhosilvatech.com.br/api/integracoes/vendas \
-H "X-Api-Key: $FORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"origem": "loja-virtual",
"idExterno": "PED-1234",
"dataVenda": "2026-11-03T10:00:00Z",
"cliente": {
"nome": "Maria Silva",
"cpfCnpj": "123.456.789-09",
"email": "[email protected]",
"telefone": "11999998888"
},
"itens": [
{ "sku": "GAT-01", "descricao": "Gatinha articulada", "quantidade": 2, "precoUnitario": 50.00 }
],
"frete": 20.00,
"desconto": 10.00,
"pagamento": { "forma": "pix" }
}'O que a integração deve saber
- Envie só vendas pagas. O pedido nasce como pago, com baixa de estoque e aviso (se a equipe escolher) no momento da confirmação.
- Reconhecimento de cliente e produto é sugestão, não criação. Se o SKU ou o cliente não forem reconhecidos, a venda espera a equipe vincular. Na segunda venda do mesmo SKU, o produto já vem vinculado.
- Mantenha o
idExternoestável. Para a mesma venda, sempre o mesmo valor; é o que impede duplicidade. - Ainda não existe consulta de status por API, endpoint para cancelar ou alterar uma venda já enviada, nem webhook de retorno. A conferência e o acompanhamento são feitos na tela do Forge.
Leads e tags
Envie leads (cadastros, carrinhos abandonados, compradores) com tags e dados. Uma campanha de e-mail ou WhatsApp cuja tag de entrada seja uma dessas tags inscreve o lead no fluxo automaticamente. Quando o lead sai do fluxo (por exemplo, comprou), a sua aplicação avisa e o Forge cancela os envios pendentes.
Criar ou atualizar um lead
POST /api/integracoes/contatos
O lead é identificado pelo e-mail, único por empresa. Se existir, é atualizado; se não, é criado. A chamada é idempotente.
| Campo | Tipo | Obrigatório | Regras |
|---|---|---|---|
email | texto | Sim | E-mail válido, até 254 caracteres. Guardado em minúsculas. |
nome | texto | Não | Até 200 caracteres. Ausente não apaga o nome já salvo. |
telefone | texto | Não | De 10 a 15 dígitos (de preferência com o código do país: 5511999999999). Fora disso é ignorado em silêncio e o lead é salvo mesmo assim. |
tags | lista de texto | Não | Até 20 por requisição, até 50 caracteres cada. Normalizadas para minúsculas. |
dados | objeto texto→texto | Não | Variáveis usadas nas mensagens ({{produto}}). Até 30 campos; todos os valores devem ser texto (envie "149.90", não 149.90). |
aceitaEmail, aceitaWhatsapp | booleano | Não | Consentimento. Ausente mantém o valor atual; em lead novo assume verdadeiro (WhatsApp só se houver telefone válido). |
origemConsentimento | texto | Não | Até 100 caracteres, ex.: checkout. Padrão: integracao. |
curl -X POST https://forge.carvalhosilvatech.com.br/api/integracoes/contatos \
-H "X-Api-Key: $FORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"nome": "Maria Souza",
"telefone": "(11) 99999-0000",
"tags": ["carrinho-abandonado"],
"dados": {
"produto": "Suporte de headset 3D",
"valor_carrinho": "89.90",
"link_carrinho": "https://loja.exemplo.com/carrinho/retomar/abc123"
},
"aceitaEmail": true,
"aceitaWhatsapp": true,
"origemConsentimento": "checkout"
}'Resposta 200: data.contatoId, data.criado (verdadeiro se o lead é novo) e data.inscricoesCriadas (ids das inscrições criadas nesta chamada; lista vazia é normal e não é erro).
Consentimento é responsabilidade da loja (LGPD). Envie true somente se o cliente concordou. Quem se descadastrou nunca volta a consentir por esta API.
Tirar o lead do fluxo
POST /api/integracoes/contatos/remover-tags
Remove as tags e cancela as inscrições ativas, e os envios ainda agendados, das campanhas cuja tag de entrada foi removida. É idempotente: e-mail ou tag inexistente não é erro.
curl -X POST https://forge.carvalhosilvatech.com.br/api/integracoes/contatos/remover-tags \
-H "X-Api-Key: $FORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "[email protected]", "tags": ["carrinho-abandonado"] }'Resposta 200: contatoEncontrado, tagsRemovidas e inscricoesCanceladas.
Regra de ouro: todo evento que abre um fluxo precisa de um evento que o fecha. Se você envia carrinho-abandonado, chame remover-tags quando a compra acontecer, ou o cliente continuará recebendo lembretes.
Avisos de WhatsApp
POST /api/integracoes/notificacoes
Pede ao Forge que envie uma mensagem de WhatsApp a um cliente, pelo número conectado da empresa (em WhatsApp → Conexão). A resposta é assíncrona: 202 significa recebido e na fila, não entregue.
| Campo | Tipo | Obrigatório | Regras |
|---|---|---|---|
telefone | texto | Sim | Com DDD, qualquer formatação. Mínimo de 10 dígitos. Com 10 ou 11 dígitos, o Forge acrescenta 55. |
mensagem | texto | Sim | Até 1.000 caracteres. Aceita a formatação do WhatsApp (*negrito*, _itálico_). |
referencia | texto | Não | Até 100 caracteres. Evita envio duplicado: com a mesma referência, a resposta traz duplicada: true. Uma referência usada nunca é reaproveitada, mesmo se o envio falhou; para reenviar, use outra (pedido-123-enviado-2). |
curl -X POST https://forge.carvalhosilvatech.com.br/api/integracoes/notificacoes \
-H "X-Api-Key: $FORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"telefone": "(11) 99999-9999",
"mensagem": "Olá, Maria! Seu pedido *#123* foi enviado.",
"referencia": "pedido-123-enviado"
}'- Limite: 200 mensagens a cada 24 horas por empresa (janela móvel). Acima disso,
429. - Entrega: o Forge envia a fila a cada minuto. Se falhar, tenta no total 3 vezes (esperas de 15 e 30 minutos) e então marca como Falhou. Acompanhe em WhatsApp → Avisos aos clientes → Últimos envios.
- Ainda não existe consulta de status por API nem webhook de retorno.
- Envie só mensagens de transação (pedido, pagamento, entrega) para quem espera o contato. Mensagens em massa aumentam o risco de bloqueio do número pelo WhatsApp.
Boas práticas
- Chave de API em variável de ambiente, usada apenas no servidor.
- Envio em segundo plano, com timeout e repetição só para timeout,
429e5xx. idExterno, e-mail ereferenciaestáveis e únicos por evento, para a repetição nunca duplicar.- Sem dados pessoais nem chave de API em logs.
- Uma chave por aplicação; revogue na hora se houver suspeita de vazamento (crie outra e atualize a aplicação).
- Teste com uma venda de teste e confira em Vendas → Vendas recebidas antes de ligar em produção. Reenvie a mesma venda para confirmar que
duplicadavem verdadeiro.
Dúvidas ou algo que a API ainda não cobre? Escreva para [email protected] com o id retornado pela chamada e o horário.