# Browser profiles

OpenIntents buys in a real browser, and each payer keeps a **browser profile**
there: the logins, cookies and carts their intents and
[sessions](/docs/sessions) build up. A shop that has seen the payer before
finds them signed in, with their cart where they left it.

Your account has one profile, and so does each of your customers. A profile is
made the first time an intent or a session needs it; you can also make one
ahead of time.

## The profile object

```json
{
  "id": "prf_7c1d04e2a9b3",
  "object": "profile",
  "customer": "cus_42",
  "status": "in_use",
  "lease": {
    "holder": { "type": "session", "id": "ses_51f0e2" },
    "expires_at": "2026-10-13T08:41:30Z"
  },
  "size_bytes": 1843200,
  "created_at": "2026-10-01T08:30:00Z",
  "last_used_at": "2026-10-13T08:30:02Z"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Unique ID, prefixed `prf_`. It says nothing about whose profile it is. |
| `customer` | string | The customer it belongs to; `null` for your account's own. |
| `status` | string | One of the statuses below. |
| `lease` | object | While an intent or a session uses it: what (`holder`) and until when (`expires_at`). Otherwise `null`. |
| `size_bytes` | integer | The saved profile's size; `null` before anything is saved. |
| `last_used_at` | string | When an intent or a session last took it. |

| Status | Meaning |
| --- | --- |
| `ready` | Nothing uses it. |
| `in_use` | An intent or a session holds it (see `lease`). |
| `forgetting` | Being erased. |
| `forgotten` | Erased, and nothing saved in it since. |

## One use at a time

A profile is used by one intent or session at a time, so a shop never sees
the same payer in two places at once. An intent waits its turn. Opening a
[session](/docs/sessions) on a profile in use answers `409` with
`code: profile_busy`, and the error's `lease` says what uses it and when its
lease next runs out. An intent waiting for a [payment link](/docs/wallets#when-a-purchase-waits)
does not hold its profile.

## List profiles

<Endpoint method="GET" path="/v1/profiles?customer=cus_42" />

Your account's profile and your customers' that exist so far, newest first.
`customer` narrows it to one customer's.

## Make a profile

<Endpoint method="POST" path="/v1/profiles" />

Send `{}` for your account's own profile, or `{ "customer": "cus_42" }`.
Optional: an intent makes the profile it needs by itself. Making one that
exists returns it unchanged, with `200` instead of `201`.

## Retrieve a profile

<Endpoint method="GET" path="/v1/profiles/{id}" />

## Forget a profile

<Endpoint method="DELETE" path="/v1/profiles/{id}" />

Erases everything the profile kept: logins, cookies, saved data. It answers
`202` with the profile `forgetting`, also while an intent or a session still
finishes with it, then it shows `forgotten`. The next intent or session starts
from an empty profile. Forgetting twice is fine.

Profiles are reachable only with your account's keys: another account's
profile is a `404`.
