> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nemu.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Integração via Bucket

> Envie dados de vendas e eventos de jornada para a Nemu por meio de um bucket na nuvem (AWS S3 ou Google Cloud Storage)

## O que é a integração via Bucket?

A integração via **Bucket** é o método de integração para operações enterprise que já centralizam seus dados em um data warehouse (ex.: BigQuery). Em vez de usar uma integração nativa ou a API, o cliente exporta periodicamente os dados de **vendas** e de **eventos de jornada** (web e app) para um bucket na nuvem (**AWS S3** ou **Google Cloud Storage**) e a Nemu lê esses arquivos diretamente de lá.

## Acesso ao bucket

<Tabs>
  <Tab title="AWS (S3)">
    A Nemu cria uma **role IAM** dedicada ao cliente e informa o ARN (ex.: `arn:aws:iam::<conta-nemu>:role/<cliente>-s3-bucket-access`). O cliente então:

    1. Libera o acesso de **leitura** dessa role no bucket (bucket policy);
    2. Confirma com a Nemu o **nome do bucket**, a **pasta (prefixo)** e a **região** (ex.: `us-east-1`).

    <Tip>Alternativamente, o cliente pode criar a role do lado dele e compartilhar o acesso com a Nemu.</Tip>
  </Tab>

  <Tab title="GCP (Cloud Storage)">
    A Nemu fornece a identidade (**service account**) que precisa de permissão de leitura no bucket. O cliente:

    1. Concede à service account da Nemu o papel de leitura de objetos (`roles/storage.objectViewer`) no bucket;
    2. Confirma com a Nemu o **nome do bucket**, a **pasta (prefixo)** e a **região/localização**.
  </Tab>
</Tabs>

## Formato dos arquivos

O formato utilizado é o **NDJSON** (um objeto JSON por linha): ele representa estruturas aninhadas (como a lista de `products`) sem ambiguidade e é exportado nativamente pelo BigQuery.

<Warning>
  O envio em **CSV** é possível, mas o layout do arquivo precisa ser validado
  com a Nemu antes de iniciar o envio.
</Warning>

<Info>
  No NDJSON o tipo do valor importa: número vai sem aspas (ex.: `"campaign_id":
      120210948573`, `"netValue": 699.99`) e texto vai com aspas (ex.: `"content":
      "CARROSSEL_1080x1080"`). No CSV tudo é texto, a Nemu converte pelo tipo do
  campo no mapeamento. Se o tipo vier errado (ex.: número como texto), o
  mapeamento acusa antes de importar.
</Info>

### Estrutura de pastas no bucket

Dentro do prefixo combinado, organize os arquivos por jornada e por data. As pastas das jornadas são `sales/` (vendas) e `events/` (eventos de jornada):

```text theme={null}
acme-analytics-exports/
└── nemu/
    ├── sales/            ← vendas
    │   └── 2026/03/14/   ← ano / mês / dia
    │       └── pedidos.ndjson
    └── events/           ← eventos de jornada
        └── 2026/03/14/
            └── eventos.ndjson
```

<Info>
  A Nemu roda as importações automaticamente, em horários de baixo pico. Você
  não precisa agendar nada.
</Info>

## Schema de vendas

Cada registro representa um pedido (ou um pedido por seller, no caso de marketplaces, veja [Multi-seller](#multi-seller-marketplaces)). O `products[]` é opcional, mas se enviado precisa de ao menos 1 item.

### Exemplo

Um pedido com dois produtos:

```json Pedido com dois produtos theme={null}
{
  "transactionId": "155480144",
  "name": "Tênis Adidas Dropset 4 Power Trainer Masculino",
  "netValue": 789.89,
  "grossValue": 789.89,
  "quantity": 1,
  "status": "paid",
  "paymentType": "credit_card",
  "customerName": "João Silva",
  "customerEmail": "cliente@email.com",
  "date": "2026-06-28",
  "subscriptionId": "",
  "customerPhone": "+55 11 98888-7777",
  "orderCreatedAt": "2026-06-28 19:39:16",
  "priceCost": 470.00,
  "utm_source": "google",
  "utm_medium": "cpc",
  "utm_campaign": "PMAX_CALCADOS_JUN",
  "utm_content": "CARROSSEL-IMAGEM_1080x1080",
  "utm_term": "tênis adidas dropset",
  "isFromApp": false,
  "coupons": ["CUPOM10"],
  "products": [
    {
      "productId": "FBA-83CC-256-42",
      "name": "Tênis Adidas Dropset 4 Power Trainer Masculino",
      "quantity": 1,
      "netValue": 699.99,
      "grossValue": 699.99,
      "priceCost": 420.00,
      "brand": "Adidas",
      "category": { "id": "15", "name": "Calçados" }
    },
    {
      "productId": "MEIA-77AB-40",
      "name": "Meia Esportiva Nike (Cano Alto)",
      "quantity": 1,
      "netValue": 89.90,
      "grossValue": 89.90,
      "priceCost": 50.00,
      "brand": "Nike",
      "category": { "id": "22", "name": "Acessórios" }
    }
  ]
}
```

### Campos do pedido

| Campo | Tipo | Obrigatório | Descrição |
| - | - | - | - |
| `transactionId` | string | ✅ | Identificador único do pedido (chave de deduplicação) |
| `parentOrderId` | string | ➖ | Id do pedido pai, agrupa filhos de sellers diferentes (marketplace, veja [Multi-seller](#multi-seller-marketplaces)) |
| `name` | string | ✅ | Nome do pedido / produto principal |
| `netValue` | number | ✅ | Receita **líquida** do pedido |
| `grossValue` | number | ✅ | Receita **bruta** do pedido |
| `quantity` | number | ✅ | Quantidade total de itens |
| `status` | string | ✅ | Status do pedido: `paid`, `waiting_payment`, `cancelled`, `chargeback`, `refunded` ou `checkout_completed` |
| `paymentType` | string | ✅ | Método de pagamento: `billet`, `credit_card`, `pix` ou `others` |
| `customerName` | string | ✅ | Nome do cliente |
| `customerEmail` | string | ✅ | E-mail do cliente. Aceita texto puro ou um valor em hash do e-mail (ex.: SHA-256) |
| `date` | string | ✅ | Data do pedido no formato `YYYY-MM-DD` |
| `subscriptionId` | string | ➖ | Identificador da assinatura, quando aplicável |
| `customerPhone` | string | ➖ | Telefone do cliente |
| `orderCreatedAt` | string | ➖ | Momento de criação do pedido no formato `YYYY-MM-DD HH:mm:ss` |
| `priceCost` | number | ➖ | Custo do produto (usado para cálculo de margem) |
| `utm_source` | string | ➖ | UTM source da venda |
| `utm_medium` | string | ➖ | UTM medium da venda |
| `utm_campaign` | string | ➖ | UTM campaign da venda |
| `utm_content` | string | ➖ | UTM content da venda |
| `utm_term` | string | ➖ | UTM term da venda, que carrega os dados de atribuição empacotados da Nemu (veja [Configuração de UTMs](/pages/bucket/configuracao-utms)) |
| `isFromApp` | boolean | ➖ | `true` quando a venda ocorreu no aplicativo |
| `coupons` | array | ➖ | Lista de códigos de cupons de desconto aplicados ao pedido (ex.: `["CUPOM10"]`) |
| `products` | array | ➖ | Lista de produtos do pedido (mínimo 1 item quando enviada), veja abaixo |

### Campos de cada produto (`products[]`)

| Campo | Tipo | Obrigatório | Descrição |
| - | - | - | - |
| `productId` | string | ✅ | Identificador único do produto (SKU) |
| `name` | string | ✅ | Nome do produto |
| `netValue` | number | ✅ | Valor líquido unitário |
| `grossValue` | number | ✅ | Valor bruto unitário |
| `quantity` | integer | ✅ | Quantidade (mínimo `1`) |
| `priceCost` | number | ➖ | Custo do produto |
| `brand` | string | ➖ | Marca do produto (ex.: `Adidas`) |
| `category` | object | ➖ | Categoria do produto |
| `category.name` | string | ✅\* | Nome da categoria (\*obrigatório se `category` for enviado) |
| `category.id` | string | ➖ | Identificador da categoria |
| `category.imageUrl` | string | ➖ | URL da imagem da categoria |

### Multi-seller (marketplaces)

Para operações marketplace, cada **pedido filho (por seller)** é enviado como um registro próprio, ligado ao pedido "pai" pelos campos:

| Campo | Tipo | Descrição |
| - | - | - |
| `transactionId` | string | Id do pedido filho, usado como chave de dedup (ex.: `155480144-1`) |
| `parentOrderId` | string | Id do pedido pai que agrupa os sellers |

O pedido pai não precisa ser enviado nem ter status próprio: o `status` vem em cada filho, e a Nemu agrupa por `parentOrderId`, somando ou subtraindo cada filho conforme o status (entregue conta, cancelado ou devolvido sai). Esses campos são opcionais: quem não é marketplace simplesmente não envia `parentOrderId`.

No exemplo abaixo, o pedido `155480144` tem itens de dois sellers e é enviado como dois pedidos filhos:

```json Pedido filho 1 theme={null}
{
  "transactionId": "155480144-1",
  "parentOrderId": "155480144",
  "name": "Tênis Adidas Dropset 4",
  "netValue": 699.99,
  "grossValue": 699.99,
  "quantity": 1,
  "status": "paid",
  "paymentType": "credit_card",
  "customerName": "João Silva",
  "customerEmail": "cliente@email.com",
  "date": "2026-06-28",
  "orderCreatedAt": "2026-06-28 19:39:16",
  "isFromApp": false,
  "products": [
    {
      "productId": "FBA-83CC-256-42",
      "name": "Tênis Adidas Dropset 4",
      "quantity": 1,
      "netValue": 699.99,
      "grossValue": 699.99,
      "priceCost": 420.0,
      "category": { "id": "15", "name": "Calçados" }
    }
  ]
}
```

```json Pedido filho 2 theme={null}
{
  "transactionId": "155480144-2",
  "parentOrderId": "155480144",
  "name": "Meia Esportiva Nike (Cano Alto)",
  "netValue": 49.9,
  "grossValue": 49.9,
  "quantity": 2,
  "status": "cancelled",
  "paymentType": "credit_card",
  "customerName": "João Silva",
  "customerEmail": "cliente@email.com",
  "date": "2026-06-28",
  "orderCreatedAt": "2026-06-28 19:39:16",
  "isFromApp": false,
  "products": [
    {
      "productId": "MEIA-77AB-40",
      "name": "Meia Esportiva Nike",
      "quantity": 2,
      "netValue": 24.95,
      "grossValue": 24.95,
      "category": { "id": "22", "name": "Acessórios" }
    }
  ]
}
```

<Info>
  No arquivo **NDJSON**, cada um desses registros ocupa **uma única linha**. A
  formatação acima é apenas para leitura.
</Info>

<Tip>
  Sub-pedidos do mesmo pedido pai podem ter **status diferentes** (ex.: um
  seller `paid` e outro `cancelled`). Envie o status real de cada sub-pedido.
</Tip>

## Schema de eventos de jornada

Os eventos de jornada (web e app) seguem o padrão de exportação do GA4/BigQuery. Cada registro representa **um evento**. O `user_pseudo_id` quase sempre existe; o `user_id` só quando o usuário fez login. O `transaction_id` costura o evento de compra com a venda.

### Exemplo

Um evento de compra com atribuição completa:

```json Evento purchase theme={null}
{
  "event_date": "2026-07-11",
  "event_timestamp": "2026-07-11 16:53:56",
  "user_pseudo_id": "00de56a47fde1207286aa3325eb6714d",
  "user_id": "2c17315c-8e85-4b71-825a-02c63a0db79d",
  "session_id": "1783788836",
  "platform": "WEB",
  "event_name": "purchase",
  "transaction_id": "155480144",
  "source": "google",
  "medium": "cpc",
  "campaign_name": "RTG_VSA_SMART_VALOR_PANGLE",
  "campaign_id": 120210948573,
  "term": "tênis nike",
  "content": "CARROSSEL-IMAGEM_1080x1080",
  "gclid": "Cj0KCQjw_8mHBhClARIsAP",
  "channel_group": "Paid Search",
  "item_id": "D74-58FP-008"
}
```

### Campos do evento

| Campo | Tipo | Obrigatório | Descrição |
| - | - | - | - |
| `event_date` | string | ✅ | Data do evento no formato `YYYY-MM-DD` (ex.: `2026-07-11`) |
| `event_timestamp` | string | ✅ | Momento exato do evento, no formato `YYYY-MM-DD HH:mm:ss`, usado para ordenar a jornada |
| `user_pseudo_id` | string | ✅ | Id anônimo do dispositivo/navegador (ex.: `00de56a47fde1207286aa3325eb6714d`) |
| `user_id` | string | ➖ | Id do usuário logado (apenas quando houve login) |
| `session_id` | string | ➖ | Id da sessão/visita, que costura os eventos da mesma navegação (ex.: `1783788836`) |
| `platform` | enum | ✅ | Onde o evento ocorreu: `WEB`, `ANDROID` ou `IOS` |
| `event_name` | enum | ✅ | Ação do evento (habilita o funil): `page_view`, `view_item`, `add_to_cart`, `begin_checkout`, `add_shipping_info`, `add_payment_info` ou `purchase` |
| `transaction_id` | string | ➖ | Id do pedido no evento `purchase`, a **ponte entre jornada e venda** (ex.: `155480144`) |
| `source` | string | ➖ | Origem do tráfego (ex.: `google`, `tiktok`, `facebook`) |
| `medium` | string | ➖ | Meio/canal do tráfego (ex.: `cpc`, `organic`, `email`, `catalogo`) |
| `campaign_name` | string | ➖ | Nome da campanha de marketing (ex.: `RTG_VSA_SMART_VALOR_PANGLE`) |
| `campaign_id` | number | ➖ | Id numérico da campanha, mais confiável que o nome (ex.: `120210948573`) |
| `term` | string | ➖ | Palavra-chave/termo de busca ou segmento (ex.: `tênis nike`) |
| `content` | string | ➖ | Variação/criativo do anúncio clicado (ex.: `CARROSSEL-IMAGEM_1080x1080`) |
| `gclid` | string | ➖ | Google Click Id, que casa o clique com o custo do Google Ads |
| `channel_group` | enum | ➖ | Agrupamento de canal calculado pelo GA4: `Paid Social`, `Paid Search`, `Organic`, `Direct` ou `Unassigned` |
| `item_id` | string | ➖ | Id do produto do evento, possível ponte com o `productId` da venda (ex.: `D74-58FP-008`) |

<Info>
  O `transaction_id` do evento `purchase` deve ser o mesmo `transactionId`
  enviado no arquivo de vendas. É ele que conecta a jornada de navegação à
  venda dentro da Nemu.
</Info>

## Configuração de UTMs

Nesta integração, a configuração de UTMs **não segue o padrão do onboarding da Nemu**. Como os campos `utm_source`, `utm_medium`, `utm_campaign` e `utm_content` geralmente já estão em uso pelo GA4 do cliente e não podem ser alterados, toda a atribuição da Nemu (origem, campanha, conjunto e criativo) é **empacotada em um único `utm_term`**, que o GA4 captura e repassa para a Nemu.

Veja o passo a passo por plataforma (Meta, Google e TikTok) em [Configuração de UTMs](/pages/bucket/configuracao-utms).

## Checklist de validação

Após o início do envio dos arquivos, cliente e Nemu validam juntos os dados carregados na plataforma:

1. **Métodos de pagamento:** todos os métodos do cliente estão mapeados corretamente para `billet`, `credit_card`, `pix` ou `others`;
2. **Receita:** valores de receita **líquida** (`netValue`) e **bruta** (`grossValue`) conferem com a plataforma do cliente;
3. **Produtos:** nome, quantidade e valores de cada produto estão corretos;
4. **Pedidos:** `transactionId` e receita de cada pedido conferem;
5. **UTMs:** o `utm_term` está chegando no **padrão de atribuição empacotado da Nemu** (veja [Configuração de UTMs](/pages/bucket/configuracao-utms)).

<Warning>
  A integração só é considerada concluída após todos os itens do checklist serem
  validados pelos dois lados. Divergências de receita ou de mapeamento de
  pagamento devem ser corrigidas na origem (exportação do cliente) antes do
  go-live.
</Warning>
