---
title: Endpoints de aplicativos, links e ativos
description: Referência A3a com parâmetros e exemplos de request e response.
---

Estas 25 operações estão em homologação em `https://api.staging.agilink.io/v1`. Exemplos usam recursos fictícios. A referência interativa contém os schemas completos de cada campo, inclusive objetos internos. Leia também o [guia da integração](/api/apps-links-ativos/) e a [migração de tokens](/api/migracao-tokens/).

Todas as requisições usam `Authorization: Bearer <credencial>`. Sessão humana e chave limitada são indicadas por operação. OAuth depende da Tarefa 2. Mutações exigem `Idempotency-Key` UUID v4; revisões, quando exigidas, usam `If-Match: "<revision>"`. Nunca envie credenciais em query strings.

## GET /links

Listar/buscar por app, domínio, grupo, estado, tags, pasta, campanha e período.

Permissão: `links:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | query | sim | OpaqueId |
| `cursor` | query | não | Cursor |
| `limit` | query | não | integer |
| `group` | query | não | — |
| `domain` | query | não | Domain |
| `q` | query | não | string |
| `order` | query | não | string |
| `prefix` | query | não | string |
| `origin` | query | não | — |
| `createdFrom` | query | não | string |
| `createdTo` | query | não | string |
| `folderId` | query | não | string |
| `campaignId` | query | não | string |
| `tagId` | query | não | string |
| `state` | query | não | string |
| `archived` | query | não | string |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": [
    {
      "id": "go.example.com~-ofertas~-tenis",
      "appId": "app_loja",
      "domain": "go.example.com",
      "prefix": "ofertas",
      "slug": "tenis",
      "url": "https://go.example.com/ofertas/tenis",
      "title": "Tênis da campanha",
      "description": null,
      "imageUrl": null,
      "desktopUrl": "https://shop.example.com/produtos/tenis",
      "appPath": "produtos/tenis",
      "parameters": {},
      "webOnly": false,
      "behavior": "manual",
      "group": "operational",
      "origin": "api",
      "revision": "20000000-0000-4000-8000-000000000001",
      "createdAt": "2026-10-19T20:00:00Z",
      "updatedAt": "2026-10-19T20:00:00Z",
      "publication": {
        "status": "pending",
        "desiredRevision": "20000000-0000-4000-8000-000000000001",
        "confirmedRevision": null,
        "updatedAt": "2026-10-19T20:00:00Z"
      }
    }
  ],
  "pagination": {
    "nextCursor": null,
    "hasMore": false
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## POST /links

Criar link web/deep link com idempotência.

Permissão: `links:create`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `appId` | string | sim | Máximo 500 caracteres |
| `domain` | Domain | sim | Consulte o schema para restrições e campos internos |
| `prefix` | string | não | Máximo 200 caracteres |
| `slug` | string | sim | Máximo 200 caracteres |
| `folderId` | string / null | não | Consulte o schema para restrições e campos internos |
| `campaignId` | string / null | não | Consulte o schema para restrições e campos internos |
| `lifecycle` | LinkLifecycle | não | Consulte o schema para restrições e campos internos |
| `utm` | UtmParameters | não | Consulte o schema para restrições e campos internos |
| `title` | string / null | não | Consulte o schema para restrições e campos internos |
| `description` | string / null | não | Consulte o schema para restrições e campos internos |
| `imageUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `desktopUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `playStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `appStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `appPath` | string / null | não | Consulte o schema para restrições e campos internos |
| `parameters` | Parameters | não | Consulte o schema para restrições e campos internos |
| `webOnly` | boolean | não | Consulte o schema para restrições e campos internos |
| `behavior` | — | não | Valores: manual, automatic, intelligent |
| `group` | — | não | Valores: main, operational |
| `templateData` | object | não | Consulte o schema para restrições e campos internos |
| `templateSelection` | object | não | Consulte o schema para restrições e campos internos |

```json
{
  "appId": "app_loja",
  "domain": "go.example.com",
  "prefix": "ofertas",
  "slug": "tenis",
  "title": "Tênis da campanha",
  "desktopUrl": "https://shop.example.com/produtos/tenis",
  "appPath": "produtos/tenis"
}
```

Resposta: `201`. Criado. Exemplo fictício.

```json
{
  "data": {
    "id": "go.example.com~-ofertas~-tenis",
    "appId": "app_loja",
    "domain": "go.example.com",
    "prefix": "ofertas",
    "slug": "tenis",
    "url": "https://go.example.com/ofertas/tenis",
    "title": "Tênis da campanha",
    "description": null,
    "imageUrl": null,
    "desktopUrl": "https://shop.example.com/produtos/tenis",
    "appPath": "produtos/tenis",
    "parameters": {},
    "webOnly": false,
    "behavior": "manual",
    "group": "operational",
    "origin": "api",
    "revision": "20000000-0000-4000-8000-000000000001",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z",
    "publication": {
      "status": "pending",
      "desiredRevision": "20000000-0000-4000-8000-000000000001",
      "confirmedRevision": null,
      "updatedAt": "2026-10-19T20:00:00Z"
    }
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `413`, `415`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /links/{linkId}

Consultar contrato administrativo e revisão.

Permissão: `links:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `linkId` | path | sim | LinkId |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "id": "go.example.com~-ofertas~-tenis",
    "appId": "app_loja",
    "domain": "go.example.com",
    "prefix": "ofertas",
    "slug": "tenis",
    "url": "https://go.example.com/ofertas/tenis",
    "title": "Tênis da campanha",
    "description": null,
    "imageUrl": null,
    "desktopUrl": "https://shop.example.com/produtos/tenis",
    "appPath": "produtos/tenis",
    "parameters": {},
    "webOnly": false,
    "behavior": "manual",
    "group": "operational",
    "origin": "api",
    "revision": "20000000-0000-4000-8000-000000000001",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z",
    "publication": {
      "status": "pending",
      "desiredRevision": "20000000-0000-4000-8000-000000000001",
      "confirmedRevision": null,
      "updatedAt": "2026-10-19T20:00:00Z"
    }
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## PATCH /links/{linkId}

Atualizar campos mutáveis com revisão.

Permissão: `links:update`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `linkId` | path | sim | LinkId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `folderId` | string / null | não | Consulte o schema para restrições e campos internos |
| `campaignId` | string / null | não | Consulte o schema para restrições e campos internos |
| `lifecycle` | LinkLifecycle | não | Consulte o schema para restrições e campos internos |
| `utm` | UtmParameters | não | Consulte o schema para restrições e campos internos |
| `title` | string / null | não | Consulte o schema para restrições e campos internos |
| `description` | string / null | não | Consulte o schema para restrições e campos internos |
| `imageUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `desktopUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `playStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `appStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `appPath` | string / null | não | Consulte o schema para restrições e campos internos |
| `parameters` | Parameters | não | Consulte o schema para restrições e campos internos |
| `webOnly` | boolean | não | Consulte o schema para restrições e campos internos |
| `behavior` | — | não | Valores: manual, automatic, intelligent |
| `group` | — | não | Valores: main, operational |
| `templateData` | object | não | Consulte o schema para restrições e campos internos |
| `templateSelection` | object | não | Consulte o schema para restrições e campos internos |

```json
{
  "title": "Tênis em promoção"
}
```

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "id": "go.example.com~-ofertas~-tenis",
    "appId": "app_loja",
    "domain": "go.example.com",
    "prefix": "ofertas",
    "slug": "tenis",
    "url": "https://go.example.com/ofertas/tenis",
    "title": "Tênis da campanha",
    "description": null,
    "imageUrl": null,
    "desktopUrl": "https://shop.example.com/produtos/tenis",
    "appPath": "produtos/tenis",
    "parameters": {},
    "webOnly": false,
    "behavior": "manual",
    "group": "operational",
    "origin": "api",
    "revision": "20000000-0000-4000-8000-000000000001",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z",
    "publication": {
      "status": "pending",
      "desiredRevision": "20000000-0000-4000-8000-000000000001",
      "confirmedRevision": null,
      "updatedAt": "2026-10-19T20:00:00Z"
    }
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `415`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## DELETE /links/{linkId}

Exclusão autorizada com revisão e dependências.

Permissão: `links:delete`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `linkId` | path | sim | LinkId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Sem corpo de requisição.

Resposta: `204`. Removido. Corpo vazio; publicação da remoção acompanha outbox.

Sem corpo de resposta.

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /apps

Apps visíveis à credencial, com paginação.

Permissão: `apps:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `limit` | query | não | integer |
| `cursor` | query | não | Cursor |
| `q` | query | não | string |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": [
    {
      "id": "app_loja",
      "name": "Loja",
      "defaultDomain": "go.example.com",
      "desktopUrl": "https://shop.example.com/",
      "playStoreUrl": null,
      "appStoreUrl": null,
      "scheme": "loja",
      "androidPackage": "com.example.loja",
      "iosBundleId": "com.example.loja",
      "revision": "20000000-0000-4000-8000-000000000001",
      "createdAt": "2026-10-19T20:00:00Z",
      "updatedAt": "2026-10-19T20:00:00Z"
    }
  ],
  "pagination": {
    "hasMore": false,
    "nextCursor": null
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## POST /apps

Criar aplicativo com configurações iniciais.

Permissão: `apps:create`. Credencial: sessão humana.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `name` | string | sim | Máximo 100 caracteres |
| `defaultDomain` | Domain / null | não | Consulte o schema para restrições e campos internos |
| `desktopUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `playStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `appStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `scheme` | string / null | não | Consulte o schema para restrições e campos internos |
| `androidPackage` | string / null | não | Consulte o schema para restrições e campos internos |
| `iosBundleId` | string / null | não | Consulte o schema para restrições e campos internos |

```json
{
  "name": "Loja",
  "desktopUrl": "https://shop.example.com/",
  "scheme": "loja",
  "androidPackage": "com.example.loja",
  "iosBundleId": "com.example.loja"
}
```

Resposta: `201`. Criado. Exemplo fictício.

```json
{
  "data": {
    "id": "app_loja",
    "name": "Loja",
    "defaultDomain": "go.example.com",
    "desktopUrl": "https://shop.example.com/",
    "playStoreUrl": null,
    "appStoreUrl": null,
    "scheme": "loja",
    "androidPackage": "com.example.loja",
    "iosBundleId": "com.example.loja",
    "revision": "20000000-0000-4000-8000-000000000001",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `413`, `415`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /apps/{appId}

Consultar cadastro e configuração.

Permissão: `apps:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | path | sim | OpaqueId |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "id": "app_loja",
    "name": "Loja",
    "defaultDomain": "go.example.com",
    "desktopUrl": "https://shop.example.com/",
    "playStoreUrl": null,
    "appStoreUrl": null,
    "scheme": "loja",
    "androidPackage": "com.example.loja",
    "iosBundleId": "com.example.loja",
    "revision": "20000000-0000-4000-8000-000000000001",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## PATCH /apps/{appId}

Atualizar nome, destinos e campos permitidos.

Permissão: `apps:update`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | path | sim | OpaqueId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `name` | string | não | Máximo 100 caracteres |
| `defaultDomain` | Domain / null | não | Consulte o schema para restrições e campos internos |
| `desktopUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `playStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `appStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `scheme` | string / null | não | Consulte o schema para restrições e campos internos |
| `androidPackage` | string / null | não | Consulte o schema para restrições e campos internos |
| `iosBundleId` | string / null | não | Consulte o schema para restrições e campos internos |

```json
{
  "name": "Loja nova"
}
```

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "id": "app_loja",
    "name": "Loja",
    "defaultDomain": "go.example.com",
    "desktopUrl": "https://shop.example.com/",
    "playStoreUrl": null,
    "appStoreUrl": null,
    "scheme": "loja",
    "androidPackage": "com.example.loja",
    "iosBundleId": "com.example.loja",
    "revision": "20000000-0000-4000-8000-000000000001",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `415`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## DELETE /apps/{appId}

Excluir respeitando links, domínios, templates e histórico.

Permissão: `apps:delete`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | path | sim | OpaqueId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Sem corpo de requisição.

Resposta: `204`. Aplicativo sem dependências excluído; tokens legados revogados. Corpo vazio.

Sem corpo de resposta.

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /apps/{appId}/defaults

Padrões de domínio, destinos e apresentação.

Permissão: `apps:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | path | sim | OpaqueId |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "appId": "app_loja",
    "domain": "go.example.com",
    "desktopUrl": "https://shop.example.com/",
    "playStoreUrl": null,
    "appStoreUrl": null,
    "revision": "20000000-0000-4000-8000-000000000001"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## PUT /apps/{appId}/defaults

Padrões de domínio, destinos e apresentação.

Permissão: `apps:update`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | path | sim | OpaqueId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `domain` | Domain / null | sim | Consulte o schema para restrições e campos internos |
| `desktopUrl` | string / null | sim | Consulte o schema para restrições e campos internos |
| `playStoreUrl` | string / null | sim | Consulte o schema para restrições e campos internos |
| `appStoreUrl` | string / null | sim | Consulte o schema para restrições e campos internos |

```json
{
  "domain": "go.example.com",
  "desktopUrl": "https://shop.example.com/",
  "playStoreUrl": null,
  "appStoreUrl": null
}
```

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "appId": "app_loja",
    "domain": "go.example.com",
    "desktopUrl": "https://shop.example.com/",
    "playStoreUrl": null,
    "appStoreUrl": null,
    "revision": "20000000-0000-4000-8000-000000000001"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `415`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /apps/{appId}/logo

Consultar, associar e remover logo via ativo autorizado.

Permissão: `apps:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | path | sim | OpaqueId |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "appId": "app_loja",
    "asset": {
      "id": "50000000-0000-4000-8000-000000000001",
      "appId": "app_loja",
      "url": "https://images.staging.agilink.io/40000000-0000-4000-8000-000000000001/app_loja/50000000-0000-4000-8000-000000000001.png",
      "state": "active",
      "revision": "20000000-0000-4000-8000-000000000001",
      "contentType": "image/png",
      "byteSize": 68,
      "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "createdAt": "2026-10-19T20:00:00Z",
      "updatedAt": "2026-10-19T20:00:00Z"
    },
    "revision": "20000000-0000-4000-8000-000000000001"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## PUT /apps/{appId}/logo

Consultar, associar e remover logo via ativo autorizado.

Permissão: `apps:update`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | path | sim | OpaqueId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `assetId` | string | sim | uuid |

```json
{
  "assetId": "50000000-0000-4000-8000-000000000001"
}
```

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "appId": "app_loja",
    "asset": {
      "id": "50000000-0000-4000-8000-000000000001",
      "appId": "app_loja",
      "url": "https://images.staging.agilink.io/40000000-0000-4000-8000-000000000001/app_loja/50000000-0000-4000-8000-000000000001.png",
      "state": "active",
      "revision": "20000000-0000-4000-8000-000000000001",
      "contentType": "image/png",
      "byteSize": 68,
      "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "createdAt": "2026-10-19T20:00:00Z",
      "updatedAt": "2026-10-19T20:00:00Z"
    },
    "revision": "20000000-0000-4000-8000-000000000001"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `415`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## DELETE /apps/{appId}/logo

Consultar, associar e remover logo via ativo autorizado.

Permissão: `apps:update`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | path | sim | OpaqueId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Sem corpo de requisição.

Resposta: `204`. Logo padrão desvinculado; arquivo preservado. Corpo vazio.

Sem corpo de resposta.

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## POST /links/{linkId}/duplicate

Criar novo link a partir de configuração existente.

Permissão: `links:create`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `linkId` | path | sim | LinkId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `slug` | string | sim | Máximo 200 caracteres |
| `prefix` | string | não | Máximo 200 caracteres |
| `domain` | Domain | não | Consulte o schema para restrições e campos internos |
| `title` | string / null | não | Consulte o schema para restrições e campos internos |

```json
{
  "slug": "tenis-copia"
}
```

Resposta: `201`. Criado. Exemplo fictício.

```json
{
  "data": {
    "id": "go.example.com~-ofertas~-tenis",
    "appId": "app_loja",
    "domain": "go.example.com",
    "prefix": "ofertas",
    "slug": "tenis",
    "url": "https://go.example.com/ofertas/tenis",
    "title": "Tênis da campanha",
    "description": null,
    "imageUrl": null,
    "desktopUrl": "https://shop.example.com/produtos/tenis",
    "appPath": "produtos/tenis",
    "parameters": {},
    "webOnly": false,
    "behavior": "manual",
    "group": "operational",
    "origin": "api",
    "revision": "20000000-0000-4000-8000-000000000001",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z",
    "publication": {
      "status": "pending",
      "desiredRevision": "20000000-0000-4000-8000-000000000001",
      "confirmedRevision": null,
      "updatedAt": "2026-10-19T20:00:00Z"
    }
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `413`, `415`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## POST /links/validate

Validar entrada e indicar conflitos conhecidos sem reservar endereço.

Permissão: `links:validate`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `appId` | string | sim | Máximo 500 caracteres |
| `domain` | Domain | sim | Consulte o schema para restrições e campos internos |
| `prefix` | string | não | Máximo 200 caracteres |
| `slug` | string | sim | Máximo 200 caracteres |
| `folderId` | string / null | não | Consulte o schema para restrições e campos internos |
| `campaignId` | string / null | não | Consulte o schema para restrições e campos internos |
| `lifecycle` | LinkLifecycle | não | Consulte o schema para restrições e campos internos |
| `utm` | UtmParameters | não | Consulte o schema para restrições e campos internos |
| `title` | string / null | não | Consulte o schema para restrições e campos internos |
| `description` | string / null | não | Consulte o schema para restrições e campos internos |
| `imageUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `desktopUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `playStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `appStoreUrl` | string / null | não | Consulte o schema para restrições e campos internos |
| `appPath` | string / null | não | Consulte o schema para restrições e campos internos |
| `parameters` | Parameters | não | Consulte o schema para restrições e campos internos |
| `webOnly` | boolean | não | Consulte o schema para restrições e campos internos |
| `behavior` | — | não | Valores: manual, automatic, intelligent |
| `group` | — | não | Valores: main, operational |
| `templateData` | object | não | Consulte o schema para restrições e campos internos |
| `templateSelection` | object | não | Consulte o schema para restrições e campos internos |

```json
{
  "appId": "app_loja",
  "domain": "go.example.com",
  "prefix": "ofertas",
  "slug": "tenis",
  "title": "Tênis da campanha",
  "desktopUrl": "https://shop.example.com/produtos/tenis",
  "appPath": "produtos/tenis"
}
```

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "valid": true,
    "available": true,
    "normalized": {
      "appId": "app_loja",
      "domain": "go.example.com",
      "prefix": "ofertas",
      "slug": "tenis",
      "title": "Tênis",
      "desktopUrl": "https://shop.example.com/"
    }
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `413`, `415`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /links/availability

Consultar disponibilidade de domínio/prefixo/slug autorizado.

Permissão: `links:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | query | sim | AppId |
| `domain` | query | sim | Domain |
| `prefix` | query | não | string |
| `slug` | query | sim | string |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "appId": "app_loja",
    "domain": "go.example.com",
    "prefix": "ofertas",
    "slug": "tenis",
    "available": true
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## POST /links/{linkId}/preview

Simular destino por cenário sem gerar clique nem fazer redirect.

Permissão: `links:preview`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `linkId` | path | sim | LinkId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `at` | AnalyticsInstant | não | Consulte o schema para restrições e campos internos |
| `country` | string | não | Consulte o schema para restrições e campos internos |
| `platform` | — | sim | Valores: desktop, android, ios |
| `source` | — | não | Valores: browser, social |

```json
{
  "platform": "android",
  "source": "browser"
}
```

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "state": "active",
    "allowed": true,
    "matchedRuleId": null,
    "evaluatedAt": "2026-10-19T20:00:00Z",
    "linkId": "go.example.com~-ofertas~-tenis",
    "appId": "app_loja",
    "platform": "android",
    "mode": "android",
    "nativeUrl": "loja://produtos/tenis",
    "fallbackUrl": "https://shop.example.com/",
    "opening": "manual",
    "publication": {
      "status": "pending",
      "desiredRevision": "20000000-0000-4000-8000-000000000001",
      "confirmedRevision": null,
      "updatedAt": "2026-10-19T20:00:00Z"
    },
    "sideEffects": false
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `413`, `415`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /links/{linkId}/publication

Consultar revisão desejada/confirmada e estado de sincronização.

Permissão: `links:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `linkId` | path | sim | LinkId |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "linkId": "go.example.com~-ofertas~-tenis",
    "appId": "app_loja",
    "revision": "20000000-0000-4000-8000-000000000001",
    "status": "pending",
    "desiredRevision": "20000000-0000-4000-8000-000000000001",
    "confirmedRevision": null,
    "updatedAt": "2026-10-19T20:00:00Z"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## POST /links/{linkId}/resync

Solicitar ressincronização via outbox.

Permissão: `links:resync`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `linkId` | path | sim | LinkId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Corpo: `application/json`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |


```json
{}
```

Resposta: `202`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "linkId": "go.example.com~-ofertas~-tenis",
    "appId": "app_loja",
    "revision": "20000000-0000-4000-8000-000000000001",
    "status": "pending",
    "desiredRevision": "20000000-0000-4000-8000-000000000001",
    "confirmedRevision": null,
    "updatedAt": "2026-10-19T20:00:00Z"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `415`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /assets

Listar e fazer upload de ativos autorizados.

Permissão: `assets:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `appId` | query | sim | AppId |
| `state` | query | não | AssetStateFilter |
| `limit` | query | não | integer |
| `cursor` | query | não | Cursor |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": [
    {
      "id": "50000000-0000-4000-8000-000000000001",
      "appId": "app_loja",
      "url": "https://images.staging.agilink.io/40000000-0000-4000-8000-000000000001/app_loja/50000000-0000-4000-8000-000000000001.png",
      "state": "active",
      "revision": "20000000-0000-4000-8000-000000000001",
      "contentType": "image/png",
      "byteSize": 68,
      "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "createdAt": "2026-10-19T20:00:00Z",
      "updatedAt": "2026-10-19T20:00:00Z"
    }
  ],
  "pagination": {
    "hasMore": false,
    "nextCursor": null
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## POST /assets

Listar e fazer upload de ativos autorizados.

Permissão: `assets:create`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |

Corpo: `multipart/form-data`. Campos desconhecidos são rejeitados.

| Campo | Tipo | Obrigatório | Restrição |
| --- | --- | --- | --- |
| `appId` | AppId | sim | Consulte o schema para restrições e campos internos |
| `file` | string | sim | Consulte o schema para restrições e campos internos |

Envie `appId` como texto e `file` como bytes de PNG/JPEG; o cliente deve gerar o boundary. Não envie o placeholder abaixo como arquivo.

```json
{
  "appId": "app_loja",
  "file": "<bytes do arquivo PNG ou JPEG>"
}
```

Resposta: `201`. Criado. Exemplo fictício.

```json
{
  "data": {
    "id": "50000000-0000-4000-8000-000000000001",
    "appId": "app_loja",
    "url": "https://images.staging.agilink.io/40000000-0000-4000-8000-000000000001/app_loja/50000000-0000-4000-8000-000000000001.png",
    "state": "active",
    "revision": "20000000-0000-4000-8000-000000000001",
    "contentType": "image/png",
    "byteSize": 68,
    "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `409`, `413`, `415`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## GET /assets/{assetId}

Metadados e exclusão condicionada a referências.

Permissão: `assets:read`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `assetId` | path | sim | OpaqueId |

Sem corpo de requisição.

Resposta: `200`. Sucesso. Exemplo fictício.

```json
{
  "data": {
    "id": "50000000-0000-4000-8000-000000000001",
    "appId": "app_loja",
    "url": "https://images.staging.agilink.io/40000000-0000-4000-8000-000000000001/app_loja/50000000-0000-4000-8000-000000000001.png",
    "state": "active",
    "revision": "20000000-0000-4000-8000-000000000001",
    "contentType": "image/png",
    "byteSize": 68,
    "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "createdAt": "2026-10-19T20:00:00Z",
    "updatedAt": "2026-10-19T20:00:00Z"
  },
  "meta": {
    "requestId": "req_00000000000040008000000000000001"
  }
}
```

Erros previstos: `400`, `401`, `403`, `404`, `422`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).

## DELETE /assets/{assetId}

Metadados e exclusão condicionada a referências.

Permissão: `assets:delete`. Credencial: sessão humana ou chave de API com acesso ao aplicativo.

| Parâmetro | Local | Obrigatório | Significado |
| --- | --- | --- | --- |
| `assetId` | path | sim | OpaqueId |
| `Idempotency-Key` | header | sim | UUID v4 por intenção. Recibo por 24h. Mudança de payload/precondição retorna 409. Segredo de chave não é reexibido. |
| `If-Match` | header | sim | ETag forte obtido em consulta. Ausência 428; revisão antiga 412. |

Sem corpo de requisição.

Resposta: `204`. Bytes removidos do R2 e ativo marcado como deleted. Corpo vazio.

Sem corpo de resposta.

Erros previstos: `400`, `401`, `403`, `404`, `409`, `412`, `413`, `422`, `428`, `429`, `500`, `503`. Veja [códigos e repetição](/api/errors/).
