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

# Using Omneo ID

> Mint and use profile-scoped tokens with the ID client from @omneo/omneo-sdk.

The `ID` client is the customer-facing half of the [Omneo SDK](/dev-guides/core-setup/sdk). Use it whenever you cannot safely ship an admin token: storefronts, profile portals, in-app customer UIs, and any browser code that needs to read or update a single profile.

The full admin client lives separately. See [Using the Omneo SDK](/dev-guides/frontend/omneo-sdk) if you need server-side access to the full API.

## How it works

The flow has three steps:

<Steps>
  <Step title="Server holds an admin token">
    Your backend keeps a long-lived [Omneo API token](/dev-guides/core-setup/api-tokens), created in CX Manager.
  </Step>

  <Step title="Server mints a profile-scoped token">
    Your backend calls `id.auth.requestAuthToken({ id })`. Omneo returns a short-lived JWT (`IDToken`) bound to that single profile.
  </Step>

  <Step title="Browser uses the token">
    Your backend hands the `IDToken` to the browser, in a cookie, template variable, or theme metafield. Browser code initialises `new ID({ tenant, IDToken })` and calls `id.profile.*` methods. The token only works against the profile it was minted for.
  </Step>
</Steps>

The `ID` client targets `https://api.[tenant].getomneo.com/id/api/v1`, a different surface from the admin API.

## Server-side: minting the token

Install the SDK and call `requestAuthToken` from a trusted server. Pass the admin token only at this step.

```typescript theme={null}
import { ID } from '@omneo/omneo-sdk'

const id = new ID({
  tenant: '[tenant]',
  omneoAPIToken: process.env.OMNEO_TOKEN
})

const { token } = await id.auth.requestAuthToken({
  id: '9332c9b2-e31c-4d49-8ec3-62a9466d339c'
})
```

To mint a token by external identity, pass `id_handle`:

```typescript theme={null}
const { token } = await id.auth.requestAuthToken({
  id: '1004993MH',
  id_handle: 'magento_id'
})
```

The same request as a raw HTTP call, for callers that cannot run Node:

```shell theme={null}
curl -X POST https://api.[tenant].getomneo.com/id/api/v1/auth/token \
  -H "Authorization: Bearer ${OMNEO_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "9332c9b2-e31c-4d49-8ec3-62a9466d339c"
  }'
```

### Anonymous tokens

Omit the `id` field to mint a token with no profile association. Anonymous tokens can only create or upsert a profile, they cannot read or update an existing one.

```typescript theme={null}
const { token } = await id.auth.requestAuthToken({})
```

## Browser-side: using the token

In the browser, initialise the client with the pre-fetched `IDToken`. Never pass `omneoAPIToken` here.

```typescript theme={null}
import { ID } from '@omneo/omneo-sdk'

const id = new ID({
  tenant: '[tenant]',
  IDToken: window.omneoIDToken
})

const profile = await id.profile.get()
```

<Warning>
  Pass only `IDToken` to a browser-side `ID` instance. The `omneoAPIToken` is the admin bearer token and must stay on a server.
</Warning>

Common operations against the bound profile:

```typescript theme={null}
await id.profile.get()
await id.profile.update({ first_name: 'Jane', birth_day: 15, birth_month: 3 })

const transactions = await id.profile.transactions.list({ include: 'product' })
const rewards = await id.profile.rewards.list()
const tiers = await id.profile.tiers.list()
```

## Token helpers

The `ID` client tracks token expiry internally once a token is set on the constructor or returned by `requestAuthToken`.

| Helper                     | Returns                      | Use when                                                      |
| -------------------------- | ---------------------------- | ------------------------------------------------------------- |
| `id.auth.isTokenExpired()` | Boolean                      | Checking whether to mint a fresh token before making a call.  |
| `id.auth.getProfileID()`   | The `pid` claim from the JWT | You need the profile's UUID without making a network request. |
| `id.reset()`               | void                         | Clearing the token, for example on logout.                    |

<Note>
  `getProfileID()` decodes the JWT using Node's `Buffer`. In a browser bundle that does not polyfill `Buffer` (some lean Vite or esbuild setups), this helper throws. The rest of the `ID` surface is browser-safe.
</Note>

## Profile methods

The `id.profile` namespace operates on the profile bound to the token. No profile ID is passed.

| Method                                             | Purpose                                             |
| -------------------------------------------------- | --------------------------------------------------- |
| `get()`                                            | Fetch the bound profile.                            |
| `update(data)`                                     | Update profile fields.                              |
| `delete()`                                         | Soft-delete the profile.                            |
| `purge()`                                          | Permanently remove profile data.                    |
| `resync()`                                         | Force a resync from connected systems.              |
| `isSubscribed(channel)`, `isUnsubscribed(channel)` | Check comms subscription state.                     |
| `subscribe(channel)`, `unsubscribe(channel, opts)` | Update comms subscription state.                    |
| `redeem(amount)`                                   | Redeem an amount from the profile's reward balance. |
| `updateType(type)`                                 | Change the profile type.                            |
| `transactionProducts(params)`                      | List products from the profile's transactions.      |
| `Connection(connectionID)`                         | Accessor for a linked connected profile.            |

Sub-resources scoped to the bound profile:

`achievements`, `addresses`, `aggregations`, `attributes`, `balances`, `benefits`, `connections`, `credits`, `identities`, `interactions`, `ledgers`, `lists`, `orders`, `points`, `redemptions`, `regions`, `rewards`, `tiers`, `transactionClaims`, `transactions`.

Each sub-resource exposes the same shape as the [`Omneo` client](/dev-guides/frontend/omneo-sdk), without the profile ID argument.

## Anonymous use: create a profile

With an anonymous token, the only supported action is to create or upsert a profile. The most common pattern is a sign-up form that converts the resulting profile into a logged-in session by minting a fresh, profile-scoped token server-side.

```typescript theme={null}
await id.call({
  method: 'POST',
  endpoint: '/profiles',
  body: { first_name: 'Jane', last_name: 'Doe', email: 'jane@example.com' }
})
```

## Locations through the ID API

The ID API exposes a read-only locations endpoint, useful for store finders on a storefront. Call it through `id.call()`:

```typescript theme={null}
const locations = await id.call({
  method: 'GET',
  endpoint: '/locations',
  params: {
    'filter[is_published]': 1,
    'filter[is_permanently_closed]': 0
  }
})
```

A single location:

```typescript theme={null}
const location = await id.call({
  method: 'GET',
  endpoint: `/locations/${locationId}`
})
```

## Shopify integration

The Omneo Shopify plugin handles the mint-and-store cycle for you. It stores the `IDToken` in `localStorage` under the key `shapes:omneo:shapestoken:{customer_id}`. The `shapes:` prefix is a legacy naming artefact, preserved so that already-deployed stores keep working. Read it first, mint a fresh token if missing or expired:

```javascript theme={null}
const key = `shapes:omneo:shapestoken:${customerId}`
let token = localStorage.getItem(key)

if (!token) {
  const response = await fetch(`${pluginUrl}/api/v1/auth/token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      id: customerId,
      signature: customerSignature
    })
  })
  const data = await response.json()
  token = data.token
  localStorage.setItem(key, token)
}

const id = new ID({ tenant: '[tenant]', IDToken: token })
```

`customerSignature` is the HMAC-SHA256 of the Shopify `customer.id`, signed with the plugin secret stored in shop metafields. In Liquid:

```liquid theme={null}
{% assign customerId = customer.id %}
{% assign customerSignature = customer.id | hmac_sha256: shop.metafields.omneo.id_secret %}
```

See [Shopify authentication](/extensions/shopify/authentication) for the full flow.

## Escape hatch: `id.call()`

Use `id.call()` for any ID endpoint the SDK does not yet wrap natively. Authentication and base URL are handled for you.

```typescript theme={null}
await id.call({
  method: 'GET',
  endpoint: '/profile/balances'
})
```

The fields are the same as on `omneo.call()`. See [Using the Omneo SDK](/dev-guides/frontend/omneo-sdk#escape-hatch-call) for the reference.

## Related

* [SDK installation](/dev-guides/core-setup/sdk)
* [Using the Omneo SDK](/dev-guides/frontend/omneo-sdk)
* [Omneo SDK concept](/concepts/platform-surfaces/omneo-sdk)
* [API tokens](/dev-guides/core-setup/api-tokens)
* [Shopify authentication](/extensions/shopify/authentication)
