---
title: Shopper Identity
description: Connect-once + vaulted shopper identity — let a shopper connect a login-walled store once, or vault a guest-checkout profile, so an agent can buy on their behalf without re-asking. Per-consumer, inbound, credentials never exposed.
---

import { Callout } from "fumadocs-ui/components/callout";
import { Tabs, Tab } from "fumadocs-ui/components/tabs";

# Shopper Identity

When an agent shops on a buyer's behalf with [`codespar_shop`](/docs/concepts/meta-tools/shop), it needs the buyer's identity at the store: a logged-in session for login-walled marketplaces (Mercado Livre, iFood), or name / CPF / address for guest checkout (VTEX retailers). **Shopper identity** is the per-consumer vault that captures this once and reuses it on later purchases — so the agent never re-asks, and you never handle raw credentials.

<Callout type="info">
This is **inbound, per-consumer** identity — the *shopper's own* store account or checkout details. It is different from [Connect Links](/docs/concepts/connect-links), which run **provider OAuth** for accounts your integration connects (a seller's Mercado Pago, a merchant's Shopify). Connect Links vault API tokens; shopper identity vaults a store login session or a guest-checkout profile for buying.
</Callout>

## Two mechanisms

| Mechanism | For | What's vaulted |
|---|---|---|
| **Connect-once** | Login-walled stores with no buyer API (Mercado Livre, iFood) | A logged-in browser session the shopper creates themselves. CodeSpar stores only an **opaque context handle** — the session lives in the hosted browser layer, never in CodeSpar's database. |
| **Vaulted profile** | Guest-checkout stores (VTEX: Cobasi, Animale, Lojas Pompeia) | The buyer's checkout identity (name, email, CPF, address), **encrypted at rest** and returned **masked** on read. |

Both are driven through [`codespar_manage_connections`](/docs/concepts/meta-tools/manage-connections) and scoped per consumer (see [Scoping](#scoping)). In both cases **you never see raw credentials** — the shopper completes any login themselves, and CodeSpar hands back only opaque handles or masked data.

## Connect-once (login-walled stores)

A three-step flow where the **shopper** logs in once and CodeSpar persists the session for reuse:

```
 connect_start          shopper logs in            connect_finish
┌──────────┐  live_view ┌──────────────┐  done   ┌───────────────┐
│ your app │ ─────────▶ │ hosted login │ ──────▶ │ CodeSpar binds │
│ (agent)  │   url      │ (the shopper)│         │ context →      │
└──────────┘            └──────────────┘         │ (org,consumer) │
                                                 └───────────────┘
```

1. **`connect_start`** returns a `live_view_url` (plus a `session_id` and `context_id`). Your app surfaces this URL to the shopper.
2. **The shopper opens it and logs into their own account** (including 2FA). Neither your app nor the agent ever sees their credentials.
3. **`connect_finish`** binds the now-logged-in context to `(org, consumer)`. Later `codespar_shop` checkouts for that consumer reuse it automatically.

<Tabs items={["TypeScript", "Python"]}>

```ts tab="TypeScript"
// 1) start — surface live_view_url to the shopper
const start = await session.execute("codespar_manage_connections", {
  action: "connect_start",
  server_id: "meli",
  consumer_id: "shopper_abc",
});
// show start.live_view_url to the shopper; they log in there

// 2) after the shopper confirms they're logged in
await session.execute("codespar_manage_connections", {
  action: "connect_finish",
  server_id: "meli",
  session_id: start.session_id,
  context_id: start.context_id,
  consumer_id: "shopper_abc",
});
```

```python tab="Python"
start = session.execute("codespar_manage_connections", {
    "action": "connect_start",
    "server_id": "meli",
    "consumer_id": "shopper_abc",
})
# show start["live_view_url"] to the shopper; they log in there

session.execute("codespar_manage_connections", {
    "action": "connect_finish",
    "server_id": "meli",
    "session_id": start["session_id"],
    "context_id": start["context_id"],
    "consumer_id": "shopper_abc",
})
```

</Tabs>

## Vaulted profile (guest checkout)

For guest-checkout stores, vault the buyer's checkout identity once so the agent auto-fills it:

<Tabs items={["TypeScript", "Python"]}>

```ts tab="TypeScript"
// save once (plaintext in, masked out)
await session.execute("codespar_manage_connections", {
  action: "save_profile",
  consumer_id: "shopper_abc",
  profile: {
    buyer: { firstName: "Ana", lastName: "Lima", email: "ana@example.com", document: "12345678900", phone: "+5511999999999" },
    address: { postalCode: "01310100", street: "Av. Paulista", number: "1000", neighborhood: "Bela Vista", city: "São Paulo", state: "SP" },
  },
});

// read back — PII is masked
const p = await session.execute("codespar_manage_connections", {
  action: "get_profile",
  consumer_id: "shopper_abc",
});
// p.buyer.document -> "•••00", p.buyer.email -> "a•••@example.com"
```

```python tab="Python"
session.execute("codespar_manage_connections", {
    "action": "save_profile",
    "consumer_id": "shopper_abc",
    "profile": {
        "buyer": {"firstName": "Ana", "lastName": "Lima", "email": "ana@example.com", "document": "12345678900", "phone": "+5511999999999"},
        "address": {"postalCode": "01310100", "street": "Av. Paulista", "number": "1000", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP"},
    },
})

p = session.execute("codespar_manage_connections", {
    "action": "get_profile",
    "consumer_id": "shopper_abc",
})
# p["buyer"]["document"] -> "•••00"
```

</Tabs>

When `codespar_shop` runs `action: "checkout"` for that consumer, it loads the vaulted profile and auto-fills it (any inline `buyer` / `address` passed on the call override the stored values).

## Scoping

Every vaulted identity is keyed `org → consumer`:

- **`org`** comes from the API key on the request — your tenant.
- **`consumer_id`** identifies one shopper within your tenant. Pass it on `connect_start` / `connect_finish` / `save_profile` / `get_profile` and on `codespar_shop` checkout. If you omit it, it defaults to the session's user id — convenient for a single-shopper session, but pass it explicitly when one tenant serves many shoppers.

A consumer's vaulted identity is only ever readable within its own `org`; there is no cross-tenant visibility.

## Integration pattern

The intended shape is a **third-party app on CodeSpar**: your app owns the end-user experience (the connect button, the chat, the account screen), and CodeSpar is the credential layer underneath. Your app renders the flow and passes a `consumer_id` per shopper; CodeSpar holds the session / profile and never exposes raw credentials back to you. Each of your shoppers maps to one `consumer_id`.

<Callout type="info">
Because the relationship between your app and its shoppers is yours, your app is the data controller for that shopper data and CodeSpar is the processor. If instead a person uses CodeSpar directly (their own key, shopping for themselves), they are simply their own one-tenant org — the same flow, but they hold the consumer-facing relationship directly. Choose the arrangement that matches who owns the shopper.
</Callout>

## See also

- [codespar_shop](/docs/concepts/meta-tools/shop) — buy-side shopping that consumes the vaulted identity
- [codespar_manage_connections](/docs/concepts/meta-tools/manage-connections) — the meta-tool that drives connect-once and profile vaulting
- [Connect Links](/docs/concepts/connect-links) — provider-OAuth connections (the developer/seller side), distinct from shopper identity
- [Directed Pay](/docs/concepts/directed-pay) — per-consumer outbound payment authorization (the settlement counterpart)
