---
title: Aplicativos, links e ativos
description: Jornada básica, campos, busca, revisões, imagens e publicação em homologação.
---
A base da homologação é `https://api.staging.agilink.io/v1`. As 25 operações deste guia têm [referência com request e response](/api/endpoints-a3a/) e [OpenAPI interativo](/referencia/). Os identificadores dos exemplos são fictícios; use aplicativos e domínios que você controla nesse ambiente.

## Aplicativos e configurações padrão

Crie o aplicativo com sessão humana em `POST /apps`, informando `name`. A criação devolve `201`, `Location`, o recurso em `data` e sua revisão em `ETag`. Ela não emite um token antigo automaticamente. Emita uma chave limitada pela [fundação](/api/fundacao/) para seu servidor.

| Campo | Uso |
| --- | --- |
| `name` | Nome de apresentação, até 100 caracteres, com texto não vazio |
| `defaultDomain` | Domínio já associado e autorizado para este app; na criação deve estar ausente ou null, pois ainda não há domínio associado ao novo ID |
| `desktopUrl`, `playStoreUrl`, `appStoreUrl` | URLs HTTPS, sem usuário/senha, até 4096 caracteres; null limpa o padrão |
| `scheme` | Esquema nativo sem `://`; os esquemas de navegação/script são rejeitados |
| `androidPackage`, `iosBundleId` | Identidades dos aplicativos nativos; não instalam SDK nem validam associações de domínio |
| `revision`, `createdAt`, `updatedAt` | Metadados do servidor, somente leitura |

`GET /apps` aceita `q`, `limit` (1–100, padrão 50) e `cursor`. A busca procura no nome. Uma chave recebe somente os aplicativos autorizados. `GET /apps/{appId}` consulta um recurso; `PATCH` altera somente os campos enviados. `GET/PUT /apps/{appId}/defaults` consulta/substitui o conjunto de domínio e URLs padrão; campos omitidos no PUT são limpos. O ETag é compartilhado com o aplicativo, inclusive com o logo. Edições pelo modelo legado também alteram essa revisão.

A associação e a ativação do domínio estão disponíveis no [guia A3b](/api/dominios-templates-publicacao/). Para criar links, utilize um domínio autorizado. Alterar os padrões não modifica os valores já gravados nos links. `DELETE /apps/{appId}` exige ausência de links, domínios, templates/histórico, ativos pendentes e operações em curso. Caso contrário retorna `409` com dependências; quando permitido, revoga os tokens legados desse aplicativo na mesma transação.

## Links e identidade

`POST /links` exige `appId`, `domain` e `slug`. `prefix` é opcional. A identidade é o conjunto domínio/prefixo/slug; reserve uma nova identidade para duplicar. Os segmentos respeitam o schema e `_agilink` é reservado. O ID retornado deve ser tratado como opaco e codificado com `encodeURIComponent` ao montar uma URL.

| Campo | Semântica |
| --- | --- |
| `title`, `description` | Apresentação do link; o schema limita o tamanho |
| `imageUrl` | URL HTTPS; imagens do armazenamento Agilink devem estar ativas e pertencer ao mesmo app |
| `desktopUrl`, `playStoreUrl`, `appStoreUrl` | Destinos explícitos; quando omitidos na criação são copiados dos padrões atuais do app |
| `appPath` | Caminho relativo, sem barra inicial, interpretado pelo aplicativo |
| `parameters` | Objeto JSON de parâmetros do conteúdo; limite semântico de 16 KiB e cinco níveis de profundidade |
| `webOnly` | Solicita o fluxo web, sem tentativa de abrir o app nativo |
| `behavior` | `manual`, `automatic` ou `intelligent`; o modo inteligente considera a origem social |
| `group` | Classificação `main` ou `operational`, independente do prefixo; padrão `operational` |
| `origin` | Origem de criação, somente leitura; a API nova grava `api`, inclusive com sessão humana |
| `templateData`, `templateSelection` | Dados e seleção compatíveis com os templates existentes; exigem referências autorizadas e versões válidas. Gestão de templates será entregue no A3b |
| `revision`, `publication` | Revisão de cadastro e estado de propagação; consulte ambos |

`GET /links/{linkId}` devolve a revisão; `PATCH` exige o ETag atual e preserva campos omitidos. A identidade não é editável pelo PATCH. `DELETE` confirma a remoção SQL com `204` e enfileira a remoção no redirecionador. Repetir o mesmo DELETE pode devolver o recibo mesmo depois de o recurso deixar de existir.

`POST /links/{linkId}/duplicate` exige um `slug` novo; aceita outro domínio/prefixo autorizados e título opcional. Copia os dados compatíveis, gera nova revisão e não sobrescreve o original. `POST /links/validate` valida uma entrada de criação e consulta a disponibilidade; `GET /links/availability` consulta domínio/prefixo/slug. Esses resultados não reservam o endereço: uma criação concorrente ainda pode receber `409`.

## Busca e paginação

`GET /links` exige `appId`. Aceita `domain`, `prefix`, `group`, `origin`, `q`, `createdFrom`, `createdTo`, `order`, `limit` e `cursor`. A busca literal procura título, descrição e slug, sem distinguir maiúsculas, mas distinguindo acentos (`Tenis` não encontra `Tênis`). Os filtros são combinados. O início temporal é inclusivo e o fim exclusivo, em RFC 3339. `order` aceita `createdAt:asc` ou `createdAt:desc` (padrão).

A consulta usa paginação SQL por data/ID, sem carregar todos os links para filtrar em memória. Preserve filtros, ordenação e limite ao enviar `pagination.nextCursor`; o cursor é assinado, vinculado à credencial e expira em 15 minutos. As listas não são um snapshot imutável. Tags, pastas, campanhas e seus filtros pertencem ao A4a; parâmetros desconhecidos retornam `400`.

## Prévia e publicação

`POST /links/{linkId}/preview` recebe `platform` (`android`, `ios`, `desktop`) e `source` (`browser`, `social`). Devolve modo, URI nativa, fallback, abertura e publicação. Reutiliza as funções de URL do Worker e os valores atuais do domínio. Não dispara redirecionamento, instalação, token de recuperação ou evento analítico. `sideEffects:false` refere-se a esses efeitos de negócio; autenticação, quota, recibo e diagnóstico continuam sendo registrados.

`GET /links/{linkId}/publication` retorna `pending`, `synced` ou `failed`, com revisão desejada/confirmada. `POST /links/{linkId}/resync`, com corpo `{}`, ETag e idempotência, enfileira uma nova tentativa e retorna `202` e `Location` da publicação. Na entrega histórica A3a, o dispatcher estava desativado. O A3b ativa a propagação isolada em homologação; `201`, `202` e `204` não comprovam atualização já visível no redirecionador.

## Upload e logo

`POST /assets` recebe exatamente `appId` e `file` em `multipart/form-data`. PNG e JPEG são aceitos até 1 MiB; o servidor verifica tipo declarado e assinatura dos bytes. Nome original não determina o caminho. O limite total do multipart é 1 MiB + 64 KiB; JSON continua limitado a 32 KiB. O upload não atribui automaticamente um logo.

```sh
curl --request POST 'https://api.staging.agilink.io/v1/assets' \
  --header 'Authorization: Bearer <sua-chave-de-homologacao>' \
  --header 'Idempotency-Key: 10000000-0000-4000-8000-000000000005' \
  --form 'appId=app_loja' \
  --form 'file=@./logo.png;type=image/png'
```

```js
const form = new FormData();
form.set('appId', appId);
form.set('file', file); // File de PNG ou JPEG
const response = await fetch('https://api.staging.agilink.io/v1/assets', {
  method: 'POST',
  headers: {Authorization: `Bearer ${serverKey}`, 'Idempotency-Key': intentId},
  body: form,
});
const result = await response.json();
```

Esse código deve rodar no servidor que protege a chave. Não defina manualmente o `Content-Type`: o cliente precisa acrescentar o boundary. A [referência](/api/endpoints-a3a/) mostra o `201`, incluindo `id`, `url`, `contentType`, `byteSize`, `sha256` e `revision`.

`GET /assets?appId=...` aceita `state=active|deleting` (padrão active), `limit` e `cursor`. `GET /assets/{assetId}` consulta metadados. A URL retornada é pública por design; qualquer pessoa que a conhecer poderá ler a imagem. O bucket permanece privado e a leitura passa pelo gateway de imagens; o gateway não lista arquivos. Cadastro, consulta de metadados e remoção exigem autorização. Cada objeto tem ID aleatório e bytes imutáveis; envie outro upload para substituir a imagem.

`GET/PUT/DELETE /apps/{appId}/logo` consulta/atribui/desvincula o logo padrão. O PUT recebe `{ "assetId": "..." }`, usa o ETag do aplicativo e só aceita ativo do próprio app. O DELETE desvincula o padrão e preserva o arquivo. A propagação do padrão aos artefatos publicados será integrada no A3b.

`DELETE /assets/{assetId}` exige revisão e ausência de referências em logos, links, rascunhos e versões de templates. Retorna `409` enquanto houver dependência. A reserva `deleting` impede novas referências durante falha ou retry. O sucesso `204` confirma remoção no R2 e estado final; GET passa a retornar `404`. A homologação usa `no-store` para imagens. Snapshots de templates podem preservar referências históricas que impedem a exclusão.

## Falhas, limites e repetição

Preserve chave de idempotência, corpo/arquivo e If-Match para repetir uma intenção dentro de 24h. Novo arquivo, novo conteúdo ou nova intenção exige nova chave. Em timeout/503, o R2 pode ter confirmado o efeito: a intenção durável permite recuperar o mesmo objeto. Um recibo expirado não permite ressuscitar um ativo já excluído. Consulte o estado; não gere chaves novas em loop.

Além das quotas técnicas da [fundação](/api/fundacao/), são permitidas 20 novas intenções de upload por app por minuto, compartilhadas entre chaves. As mutações de links mantêm os limites de negócio existentes, incluindo criação de 60/min e 3000/h por app, conforme configuração; rotacionar a chave não reinicia esses contadores. Respeite `Retry-After`.

Recursos fora do usuário/app autorizado retornam `404`; permissões insuficientes retornam `403`. `428` solicita o ETag; `412` indica revisão antiga; `409` representa conflito de identidade, dependência ou idempotência. Veja [erros](/api/errors/) e envie o `X-Request-Id` ao suporte para diagnóstico.
