Pular para o conteúdo

Receitas completas de integração

Guias · v1 · Produção · Revisado em · Markdown

Use um backend com chave limitada. Os clientes de exemplo JavaScript e Python usam homologação por padrão; para produção, selecione explicitamente environment: "production" no JavaScript ou environment="production" no Python. Incluem timeout, até três tentativas com a mesma intenção, leitura de Retry-After, paginação e consulta de operações. São exemplos, não SDKs com garantia de estabilidade. Nenhuma chamada ocorre ao importar. Salve os arquivos no seu servidor e defina AGILINK_API_KEY no ambiente seguro.

Todos os 143 endpoints têm cURL, JS/TS e Python na referência por operação. Os exemplos usam IDs fictícios; substitua-os pelos recursos autorizados. Downloads são autenticados. Nunca registre o segredo de uma chave ou webhook em logs.

Criar app exige sessão humana verificada. Obtenha-a pelo login do produto, mantenha-a no servidor seguro e não use credencial administrativa de provedor. Conectar domínio depende da capacidade e autorização do app. Aguardar operação não comprova associação nativa em aparelho.

import {AgilinkClient} from './agilink-client.mjs';
const human = new AgilinkClient(process.env.AGILINK_HUMAN_SESSION);
const {data: created} = await human.request('/apps', {method:'POST',body:{name:'Minha loja'}});
const appId = created.data.id;
const {data: setup} = await human.request('/domains', {method:'POST',body:{appId,mode:'platform',prefix:'minha-loja'}});
const connected = await human.waitOperation(setup.data.id);
if (connected.status !== 'succeeded') throw Error('Confira o domínio antes de continuar.');
const domains = await human.request('/domains?appId='+encodeURIComponent(appId));
const domain = domains.data.data.find(d=>d.links==='active' && !d.detached);
if (!domain) throw Error('Aguarde propriedade, DNS e HTTPS.');
const {data: link} = await human.request('/links', {method:'POST',body:{appId,domain:domain.hostname,slug:'produto',desktopUrl:'https://shop.example.com/produto',webOnly:true}});
const publication = await human.request('/links/'+encodeURIComponent(link.data.id)+'/publication');
// Confira publication.data.data; a propagação pública é eventual.
import os
from agilink_client import AgilinkClient
human = AgilinkClient(os.environ['AGILINK_HUMAN_SESSION'])
app_id = human.request('/apps', method='POST', body={'name':'Minha loja'})['data']['data']['id']
setup = human.request('/domains', method='POST', body={'appId':app_id,'mode':'platform','prefix':'minha-loja'})
state = human.wait_operation(setup['data']['data']['id'])
if state['status'] != 'succeeded':
raise RuntimeError('Confira o domínio antes de continuar')
domains = human.request('/domains?appId='+app_id)['data']['data']
domain = next((d for d in domains if d['links'] == 'active' and not d['detached']), None)
if domain is None:
raise RuntimeError('Aguarde propriedade, DNS e HTTPS')
link = human.request('/links', method='POST', body={'appId':app_id,'domain':domain['hostname'],'slug':'produto','desktopUrl':'https://shop.example.com/produto','webOnly':True})
from urllib.parse import quote
publication = human.request('/links/'+quote(link['data']['data']['id'], safe='')+'/publication')

Aplicativos · Domínios · Abrir e medir.

import {AgilinkClient} from './agilink-client.mjs';
const api = new AgilinkClient();
for await (const links of api.pages('/links?appId=app_loja&group=operational&q=produto')) {
for (const link of links) console.log(link.id, link.title);
}
from agilink_client import AgilinkClient
api = AgilinkClient()
for links in api.pages('/links?appId=app_loja&group=operational&q=produto'):
for link in links:
print(link['id'], link['title'])

Mantenha credencial, app, filtros, ordenação e limite; cursor expira em 15 minutos. A lista pode mudar entre páginas. Para arquivo limitado na execução, use exportação.

import {AgilinkClient, AgilinkError} from './agilink-client.mjs';
const api = new AgilinkClient(), path = '/links/'+encodeURIComponent('go.example.com~-ofertas~-tenis');
const current = await api.request(path);
try { await api.request(path,{method:'PATCH',revision:current.data.data.revision,body:{title:'Título revisado'}}); }
catch (error) {
if (!(error instanceof AgilinkError) || error.status !== 412) throw error;
const latest = await api.request(path);
// Mostre latest e a intenção ao usuário; reconcilie antes de criar uma NOVA edição.
}
from agilink_client import AgilinkClient, AgilinkError
api = AgilinkClient()
path = '/links/go.example.com~-ofertas~-tenis'
current = api.request(path)
try:
api.request(path, method='PATCH', revision=current['data']['data']['revision'], body={'title':'Título revisado'})
except AgilinkError as error:
if error.status != 412:
raise
latest = api.request(path)
# Reconciliar com a pessoa antes de nova intenção; não sobrescrever cegamente.

Gere um UUID por intenção e preserve corpo, caminho, revisão e credencial em todas as tentativas. Os clientes de exemplo conservam esses valores nas até três tentativas. Se esgotar, guarde error.intentId (JS) / error.intent_id (Python) e consulte o recurso antes de decidir repetir. Para emissão de segredo, 409 secret_not_replayable exige consultar/revogar o recurso identificado; não gerar nova chave automaticamente.

import {AgilinkClient} from './agilink-client.mjs';
const api = new AgilinkClient(), intentId = crypto.randomUUID();
const body = {appId:'app_loja',domain:'go.example.com',slug:'produto',desktopUrl:'https://shop.example.com/produto'};
const result = await api.request('/links',{method:'POST',body,intentId});
// Em resultado incerto, preserve intentId e body; não chame randomUUID para o mesmo retry.
import {writeFile} from 'node:fs/promises';
import {AgilinkClient} from './agilink-client.mjs';
const api = new AgilinkClient();
const {data: saved} = await api.request('/qr-codes',{method:'POST',body:{appId:'app_loja',linkId:'go.example.com~-ofertas~-tenis',name:'Vitrine'}});
const image = await api.request('/qr-codes/'+saved.data.id+'/download?format=png',{binary:true});
await writeFile('vitrine.png',new Uint8Array(image.data));
from agilink_client import AgilinkClient
api = AgilinkClient()
saved = api.request('/qr-codes', method='POST', body={'appId':'app_loja','linkId':'go.example.com~-ofertas~-tenis','name':'Vitrine'})
image = api.request('/qr-codes/'+saved['data']['data']['id']+'/download?format=png', binary=True)
with open('vitrine.png','wb') as output:
output.write(image['data'])

Confira câmera e impressão em aparelho real. Limites do QR.

POST /campaigns com appId/name/utm → GET /links/{linkId} → PATCH com campaignId e cópia explícita de utm usando revisão → GET /analytics/campaigns/{campaignId}?start=…&end=…. Copiar UTMs não sincroniza alterações futuras. Métricas seguem associações atuais e cobertura dos eventos retidos.

import {AgilinkClient} from './agilink-client.mjs';
const api = new AgilinkClient();
const campaign = (await api.request('/campaigns',{method:'POST',body:{appId:'app_loja',name:'Verão',utm:{utm_campaign:'verao'}}})).data.data;
const path = '/links/'+encodeURIComponent('go.example.com~-ofertas~-tenis');
const link = (await api.request(path)).data.data;
await api.request(path,{method:'PATCH',revision:link.revision,body:{campaignId:campaign.id,utm:campaign.utm}});
const metric = await api.request('/analytics/campaigns/'+campaign.id+'?start=2026-10-01T00%3A00%3A00Z&end=2026-11-01T00%3A00%3A00Z');

GET /template-catalog?appId=… → POST /templates com modelo disponível → PUT /templates/{id}/draft com revisão e variáveis válidas → POST /templates/{id}/validate → POST /templates/{id}/versions para snapshot imutável → POST /templates/{id}/publish → GET /template-publications/{id} até confirmação ou falha → POST /templates/{id}/restore para versão anterior.

A publicação usa schema próprio de intenção/alvos; copie os requests validados da referência, não um objeto arbitrário. Antes de restaurar, consulte a revisão atual; restauração é nova intenção e não reescreve snapshots. Requests completos e alvos · Herança e editor.

import {AgilinkClient} from './agilink-client.mjs';
const api = new AgilinkClient();
const uploaded = (await api.request('/imports',{method:'POST',body:{appId:'app_loja',format:'csv',content:'domain,slug,desktopUrl\ngo.example.com,produto,https://shop.example.com/produto'}})).data.data;
const checked = (await api.request('/imports/'+uploaded.id+'/validate',{method:'POST',body:{}})).data.data;
const rows = (await api.request('/imports/'+uploaded.id+'/items')).data.data;
if (checked.failed) throw Error('Confira rows; corrija e envie apenas linhas necessárias em nova importação.');
const queued = (await api.request('/imports/'+uploaded.id+'/commit',{method:'POST',revision:checked.revision,body:{}})).data.data;
const outcome = await api.waitOperation(queued.operationId);
// Consulte itens novamente; parcialmente concluído não significa rollback de todos.
from agilink_client import AgilinkClient
api = AgilinkClient()
uploaded = api.request('/imports',method='POST',body={'appId':'app_loja','format':'json','content':'[{"domain":"go.example.com","slug":"produto","desktopUrl":"https://shop.example.com/produto"}]'})['data']['data']
checked = api.request('/imports/'+uploaded['id']+'/validate',method='POST',body={})['data']['data']
if checked['failed']:
raise RuntimeError('Consulte os itens e corrija as linhas')
queued = api.request('/imports/'+uploaded['id']+'/commit',method='POST',revision=checked['revision'],body={})['data']['data']
outcome = api.wait_operation(queued['operationId'])
import {writeFile} from 'node:fs/promises';
import {AgilinkClient} from './agilink-client.mjs';
const api = new AgilinkClient();
const queued = (await api.request('/exports',{method:'POST',body:{appId:'app_loja',dataset:'links',format:'csv'}})).data.data;
const operation = await api.waitOperation(queued.operationId);
if(operation.status!=='succeeded') throw Error('Confira limite, autorização e erro da operação.');
const file = await api.request('/exports/'+queued.id+'/download',{binary:true});
await writeFile('links.csv',new Uint8Array(file.data));
from agilink_client import AgilinkClient
api = AgilinkClient()
queued = api.request('/exports',method='POST',body={'appId':'app_loja','dataset':'links','format':'csv'})['data']['data']
operation = api.wait_operation(queued['operationId'])
if operation['status'] != 'succeeded':
raise RuntimeError('Confira limite, autorização e erro')
with open('links.csv','wb') as output:
output.write(api.request('/exports/'+queued['id']+'/download',binary=True)['data'])

Máximo 1.000 registros ou 1 MiB. Arquivo por 24h; download exige leitura atual do conjunto original. CSV neutraliza fórmulas: preserve essa proteção.

  1. Cadastre seu endpoint HTTPS público IPv4/443 em POST /webhooks, eventos e app. Guarde o segredo uma vez no servidor.
  2. Receba corpo bruto; valide Agilink-Signature com timestamp até 300s e HMAC-SHA256 antes de interpretar o JSON.
  3. Faça deduplicação durável por event.id em transação antes de aplicar efeito; responda 2xx rapidamente e coloque trabalho longo na sua fila.
  4. Use POST /webhooks/{id}/test; confira test:true e histórico. Timeout/3xx/5xx têm retentativas; não há ordem global.
  5. Para mudar segredo, rotacione com revisão e sobreposição, atualize receptor e só depois retire o anterior. Destino alterado cancela pendências da revisão antiga; reentrega é explícita.

Verificador HMAC completo e política de retentativas. Não exponha esse segredo no mobile ou no portal público.

Configure a associação de domínio, pacote Android/certificados e bundle iOS/team conforme sua distribuição; configure appPath relativo. Instale o SDK Flutter, trate as entradas HTTPS/scheme/colagem e registre abertura/conteúdo com IDs estáveis. App Links/Universal Links e recuperação pós-instalação são etapas distintas. Faça os testes em aparelho real pelas lojas, incluindo sem app instalado, instalado, link inválido, repetição e ausência de resultado elegível. Recebimento e parâmetros · Recuperação.

// Dentro do seu handler de URI, depois de receber pelo fluxo configurado no SDK:
void tratarUri(Uri uri) {
final produto = uri.queryParameters['produto'];
if (produto == null || produto.isEmpty) return;
// Valide o produto no backend do aplicativo antes de navegar.
}

O exemplo Dart é tratamento de parâmetro, não uma API inventada do SDK. Use as assinaturas do pacote e o guia Flutter da versão integrada.

Na área Desenvolvedores, selecione chave, revise alcance/prazo e rotacione. Via API humana: GET /api-keys/{id} → POST /api-keys/{id}/rotate com If-Match e overlapSeconds → guarde novo segredo sem log → atualize consumidor → teste leitura autorizada → DELETE da anterior se ainda vigente.

401 indica credencial/sessão/validade/revogação; 403 indica permissão/capacidade; não resolva ambos emitindo uma chave mais ampla automaticamente. Para reduzir, PATCH com subconjunto de apps/permissões/prazo. Requests humanos completos · Diagnóstico.