# API de tags de objeto (beta)

As tags de objeto armazenam dados estruturados sobre um usuário em uma única tag. Uma tag do tipo `Object` contém um objeto com campos nomeados, como o último `order` com seu `amount` e `status`. Uma tag do tipo `ObjectList` contém um array desses objetos, como todos os `orders`. Você define os campos uma vez, grava e lê os valores pela API de tags e cria segmentos pelos valores dos campos.

<Aside type="caution" title="Beta">
As tags de objeto estão em beta e disponíveis mediante solicitação. Entre em contato com o [Suporte da Pushwoosh](https://help.pushwoosh.com/hc/en-us/requests/new) para habilitá-las na sua conta. Durante o beta, as tags de objeto funcionam apenas pela API:

- O Painel de Controle não tem nenhuma tela para tags de objeto.
- Os campos das tags de objeto não podem ser inseridos no conteúdo das mensagens.
- O Customer Journey não suporta tags de objeto.
</Aside>

## Como funcionam as tags de objeto

Uma tag de objeto tem um esquema e um valor. O esquema é o nome da tag e uma lista de campos, cada um com seu próprio tipo escalar. O valor é armazenado nos campos, separadamente para cada usuário.

- **Campo.** Cada campo é uma tag com o nome `<object>.<field>`, por exemplo `order.amount`. Você segmenta por campos e pode gravar um campo de uma tag `Object` por esse nome.
- **Valor `Object`.** Um objeto por usuário, por exemplo `"order": {"amount": 120, "status": "paid"}`.
- **Valor `ObjectList`.** Um array de objetos com os mesmos campos, por exemplo `"orders": [{"amount": 120, "status": "paid"}, {"amount": 50}]`.

As tags de objeto são sempre User-specific, o que significa que o valor pertence ao usuário, não a um único dispositivo, e é copiado para todos os dispositivos do usuário. Consulte a [API de Tags](/pt/developer/api-reference/tags/) para tags comuns.

## Regras do esquema

A Pushwoosh verifica estas regras quando você cria uma tag de objeto ou adiciona um campo:

- Os nomes de objetos e campos contêm apenas letras latinas, dígitos e `_`.
- O nome completo do campo `<object>.<field>` tem 64 caracteres ou menos.
- Uma tag de objeto tem de 1 a 20 campos. Os nomes dos campos não diferenciam maiúsculas de minúsculas, portanto `Amount` e `amount` são o mesmo campo.
- Um campo tem um destes tipos: `INTEGER`, `STRING`, `LIST`, `DATE`, `BOOLEAN`, `PRICE`, `VERSION`. Campos de fuso horário e objetos aninhados não são suportados.
- Um campo não pode ter um nome que outra tag já tenha. Se existir uma tag `order.note`, adicionar o campo `note` a `order` falha com `tag order.note already exists`.
- Uma tag de objeto não pode perder seu último campo. Em vez disso, exclua a tag de objeto.
- Um campo ou uma tag de objeto em uso não pode ser excluído. O erro lista onde ele é usado, por exemplo `field is in use: segment Big buyers, in-app Spring sale`. Segmentos, in-apps, campanhas de Customer Journey em execução, presets, modelos de e-mail e outros itens que fazem referência à tag contam como usos.

## Gerenciar o esquema

Crie e altere tags de objeto com os métodos REST abaixo. Use `/json/1.3/addTag` apenas para tags comuns, porque ele não consegue definir campos.

### URL base

```
https://rpc-api.svc-nue.pushwoosh.com
```

### Autenticação

Toda solicitação deve incluir um cabeçalho `Authorization` com o seu [token de API do Servidor](/pt/developer/api-reference/api-access-token/#server-api-token). Um token de API do Dispositivo recebe HTTP 403 `a device API token cannot call this method, use an account API token`.

```
Authorization: Api YOUR_API_TOKEN
```

### Endpoints

Estes métodos gerenciam o esquema das tags de objeto:

| Método | Caminho | Descrição |
| :---- | :---- | :---- |
| `POST` | `/api/tags` | Criar uma tag de objeto com seus campos |
| `GET` | `/api/tags/{name}` | Obter uma tag de objeto com seus campos |
| `GET` | `/api/tags` | Listar tags. Uma tag de objeto vem com seus `fields`, e os campos não são listados como tags separadas |
| `POST` | `/api/tags/{name}/fields` | Adicionar um campo |
| `DELETE` | `/api/tags/{name}/fields/{field}` | Excluir um campo |
| `DELETE` | `/api/tags/{name}` | Excluir uma tag de objeto com todos os seus campos |

`POST /api/tags` e ambos os métodos de campos retornam a tag de objeto após a alteração, envolvida em `{"tag": {...}}`. `DELETE /api/tags/{name}` retorna `{}`.

Se as tags de objeto não estiverem habilitadas na sua conta, `POST /api/tags` com um tipo de objeto e ambos os métodos de campos falham com HTTP 403 `object tags are not enabled for the account`. `GET /api/tags/{name}` e `DELETE /api/tags/{name}` retornam HTTP 404 `tag not found`, e `GET /api/tags` não lista as tags de objeto. Sem as tags de objeto habilitadas, você não consegue criar nenhuma, então não há onde gravar valores.

<span id="create-an-object-tag" />

### Criar uma tag de objeto

`POST` `/api/tags`

##### Corpo da solicitação

| Nome | Tipo | Descrição |
| :---- | :---- | :---- |
| name\* | string | Nome da tag de objeto. |
| type\* | string | `OBJECT` para um objeto ou `OBJECT_LIST` para uma lista de objetos. |
| fields\* | array | Campos do objeto, de 1 a 20. |
| fields[].name\* | string | Nome do campo. O campo se torna a tag `<name>.<fields[].name>`. |
| fields[].type\* | string | Tipo do campo: `INTEGER`, `STRING`, `LIST`, `DATE`, `BOOLEAN`, `PRICE` ou `VERSION`. |

```json title="Exemplo"
{
  "name": "orders",
  "type": "OBJECT_LIST",
  "fields": [
    { "name": "amount", "type": "INTEGER" },
    { "name": "status", "type": "STRING" }
  ]
}
```

```json title="Resposta"
{
  "tag": {
    "name": "orders",
    "type": "OBJECT_LIST",
    "system": false,
    "user_specific": true,
    "has_right_ace_modify": true,
    "fields": [
      { "name": "amount", "type": "INTEGER" },
      { "name": "status", "type": "STRING" }
    ]
  }
}
```

A tag é criada como User-specific independentemente do valor de `user_specific`. `GET /api/tags/{name}` retorna o mesmo objeto sem o invólucro `tag`. Os campos são ordenados por nome.

### Adicionar um campo

`POST` `/api/tags/{name}/fields`

```json title="Exemplo: POST /api/tags/orders/fields"
{
  "field": { "name": "note", "type": "STRING" }
}
```

Você pode gravar o novo campo imediatamente como parte do valor completo da tag. Adicionar um campo falha se a tag de objeto já tiver 20 campos ou se existir uma tag com o nome completo do campo, consulte [Erros](#errors).

### Excluir um campo

`DELETE` `/api/tags/{name}/fields/{field}`

Por exemplo, `DELETE /api/tags/orders/fields/note` exclui o campo `orders.note`. Você não pode excluir o último campo nem um campo em uso, consulte [Erros](#errors).

<span id="errors" />

### Erros

Os erros vêm no formato `{"code": <n>, "message": "...", "details": [...]}`. Quando você cria uma tag de objeto, as mensagens 400 começam com `validate: `.

| Status HTTP | Mensagem | Causa |
| :---- | :---- | :---- |
| 400 | `object tag and field names must contain only letters, digits and underscores` | Um nome tem outro caractere. |
| 400 | `an object tag needs 1 to 20 fields` | Nenhum campo ou mais de 20 campos na criação. |
| 400 | `an object tag has at most 20 fields` | A tag de objeto já tem 20 campos. |
| 400 | `field <name> is given twice` | Dois campos têm o mesmo nome, ignorando maiúsculas e minúsculas. |
| 400 | `<object>.<field>: object and field names together cannot be longer than 64 characters` | O nome completo do campo é longo demais. |
| 400 | `<object>.<field>: field type must be INTEGER, STRING, LIST, DATE, BOOLEAN, PRICE or VERSION` | Tipo de campo não suportado. |
| 400 | `an object tag needs at least one field; delete the object tag instead` | Você tentou excluir o último campo. |
| 400 | `field is in use: ...`, `tag is in use: ...` | O campo ou a tag de objeto é usado em segmentos, in-apps, campanhas de Customer Journey ou outros itens. |
| 403 | `object tags are not enabled for the account` | As tags de objeto não estão habilitadas na conta. |
| 403 | `a device API token cannot call this method, use an account API token` | A solicitação usa um token de API do Dispositivo. |
| 404 | `tag not found` | `GET` ou `DELETE /api/tags/{name}`: a tag não existe, o nome é um campo ou as tags de objeto não estão habilitadas. |
| 404 | `object tag not found`, `field not found` | Métodos de campos: a tag de objeto ou o campo não existe. |
| 409 | `tag already exists` | Existe uma tag com o nome da tag de objeto. |
| 409 | `tag <object>.<field> already exists` | Existe uma tag com o nome completo do campo. |

## Gravar valores

Grave os valores das tags de objeto com [`/setTags`](/pt/developer/api-reference/device-api/#settags) e [`/bulkSetTags`](/pt/developer/api-reference/audience-api/#bulksettags). Esses métodos mantêm sua própria autenticação: `/setTags` recebe um token de API do Dispositivo no cabeçalho `Authorization: Token`, e `/bulkSetTags` recebe o token de acesso à API em `auth`. Envie um valor `Object` como um objeto JSON e um valor `ObjectList` como um array de objetos:

```json title="Exemplo: /json/1.3/setTags"
{
  "request": {
    "application": "XXXXX-XXXXX",
    "userId": "user_42",
    "tags": {
      "order": { "amount": 120, "status": "paid" },
      "orders": [
        { "amount": 120, "status": "paid" },
        { "amount": 50 }
      ]
    }
  }
}
```

Se você definir o valor por HWID, ele é armazenado no usuário desse dispositivo.

Cada campo recebe um valor no formato do seu tipo:

| Tipo de campo | Valor de exemplo |
| :---- | :---- |
| `INTEGER` | `120` |
| `STRING` | `"paid"` |
| `LIST` | `["gift", "express"]` |
| `DATE` | `"2026-10-02 22:11"` (UTC), `"2026-10-02"` ou um timestamp Unix em segundos |
| `BOOLEAN` | `true` ou `false` |
| `PRICE` | `19.95` |
| `VERSION` | `"1.0.0"` |

### A gravação substitui o valor inteiro

Cada gravação substitui o valor armazenado da tag de objeto:

- Um campo ausente no novo valor é excluído. Um campo enviado como `null` também é excluído.
- `null`, `[]` ou `""` exclui o valor inteiro.
- `{}` exclui todos os campos de uma tag `Object`.
- Uma chave que não é um campo do objeto é ignorada.
- Se o valor de um campo não corresponder ao tipo do campo, o valor inteiro da tag é rejeitado e o valor armazenado permanece como estava.

`/setTags` não informa um valor rejeitado na sua resposta. Verifique o resultado com [`/getTags`](#read-values) ou use `/bulkSetTags`, que informa um resultado para cada tag.

### Gravar um campo de um Object

Grave um único campo de uma tag `Object` pelo seu nome completo. `increment` e as outras operações de [`/setTags`](/pt/developer/api-reference/device-api/#settags) funcionam com campos:

```json
"tags": {
  "order.status": "shipped",
  "order.amount": { "operation": "increment", "value": 5 }
}
```

Um campo de uma tag `ObjectList` não pode ser gravado isoladamente, porque não fica claro qual elemento alterar. `/setTags` ignora esse valor. Em vez disso, envie a lista inteira.

### Tags de objeto não são criadas automaticamente

Um valor com um objeto ou um array de objetos para uma tag que não existe é ignorado. A criação automática de tags não cria tags de objeto, então crie o esquema primeiro com [`POST /api/tags`](#create-an-object-tag).

### Resultados de bulkSetTags

Com `detailed=true`, o [status de `/bulkSetTags`](/pt/developer/api-reference/audience-api/#bulksettags-status) retorna um destes resultados para uma tag de objeto, além de `ok`, `tag not found` e `wrong value. expect :<type>`:

| Resultado | Causa |
| :---- | :---- |
| `object tags are stored on the user only` | A tag de objeto não é User-specific. |
| `cannot load the fields of the object` | A Pushwoosh não conseguiu ler os campos da tag de objeto. |
| `wrong value. expect an object (a map) or, for a list of objects, an array of maps` | O valor não se ajusta à tag de objeto, ou o valor de um campo não corresponde ao seu tipo. |
| `a field of a list of objects cannot be set on its own, set the whole list` | O valor é definido em um campo de uma tag `ObjectList`. |

<span id="read-values" />

## Ler valores

[`/getTags`](/pt/developer/api-reference/device-api/#gettags) retorna um valor `Object` como um objeto JSON e um valor `ObjectList` como um array de objetos:

```json title="Resposta"
{
  "status_code": 200,
  "status_message": "OK",
  "response": {
    "result": {
      "order": { "amount": 120, "status": "paid" },
      "orders": [
        { "amount": 120, "status": "paid" },
        { "amount": 50 }
      ]
    }
  }
}
```

Os valores dos campos são retornados da mesma forma que os valores de tags comuns em `/getTags`: um Date como timestamp Unix em segundos, um Price como string, por exemplo `"120.00"`, e um Boolean como `1` ou `0`.

<span id="segment-by-fields" />

## Segmentar por campos

Defina as condições do segmento nos campos, não na própria tag de objeto. Na [linguagem de segmentação](/pt/developer/api-reference/segmentation-filters-api/segmentation-language/), um campo é uma tag com um nome com pontos e aceita os operadores do seu próprio tipo:

```
AT("XXXXX-XXXXX", "order.amount", gte, 100)
```

Uma condição na própria tag de objeto falha com `object tag has no value of its own, use one of its fields`.

### Condições em um ObjectList

Uma condição em um campo de uma tag `ObjectList` corresponde a um usuário quando pelo menos um elemento da lista atende à condição. Condições em campos da mesma lista unidas com AND devem corresponder ao mesmo elemento:

```
AT("XXXXX-XXXXX", "orders.amount", gte, 100) * AT("XXXXX-XXXXX", "orders.status", eq, "paid")
```

Este segmento contém usuários com pelo menos um pedido que seja ao mesmo tempo de 100 ou mais e pago. Um usuário com um pedido grande não pago e um pedido pequeno pago não corresponde. Condições unidas com OR não precisam corresponder ao mesmo elemento. Condições em duas listas diferentes são verificadas em cada lista separadamente.

Alguns operadores funcionam de forma diferente em um campo de uma tag `ObjectList`:

- **`notset`.** Nenhum elemento da lista tem um valor neste campo. Um usuário sem a lista também corresponde.
- **`noteq`.** Pelo menos um elemento tem um valor neste campo, e esse valor é diferente do informado. Elementos sem o campo não contam. Um usuário com pedidos nos status `paid` e `new` corresponde a `noteq "paid"`.
- **`notin` em um campo List.** Nenhum elemento contém nenhum dos valores informados.
- **`notin` em um campo de outro tipo.** Pelo menos um elemento tem um valor neste campo que não está entre os valores informados.

`notset` e `notin` em um campo List não estão vinculados ao mesmo elemento que as outras condições unidas com AND.

## Exportar segmentos com tags de objeto

[`/exportSegment`](/pt/developer/api-reference/segmentation-filters-api/#exportsegment) exporta os campos das tags de objeto:

- **CSV.** Cada campo é uma coluna separada com o nome `<object>.<field>`, e as próprias tags de objeto não têm coluna. Um campo de um ObjectList contém todos os valores distintos dos elementos como um array JSON, da mesma forma que uma tag List: `["120","50"]`.
- **`json` e `json_each_line`.** Os campos de uma tag `Object` vêm como tags separadas com o nome `<object>.<field>`. Uma tag `ObjectList` vem como uma entrada em `tags` com os elementos em `object_list.items`. Cada elemento lista seus campos com nomes curtos, e cada campo traz seu valor em uma chave com o nome do seu tipo: `integer`, `string`, `list`, `date`, `boolean`, `price` ou `version`. Os valores inteiros vêm como strings:

```json
{
  "name": "orders",
  "object_list": {
    "items": [
      { "fields": [{ "name": "amount", "integer": "120" }, { "name": "status", "string": "paid" }] },
      { "fields": [{ "name": "amount", "integer": "50" }] }
    ]
  }
}
```

Se `tagsList` nomear uma tag de objeto, todos os seus campos são exportados.