# Me API V3

The **Me API** answers one question: *who am I?*

Fetch the authenticated user's own details using your API key and access token. Call it with nothing but your credentials and it returns the profile of the user those credentials belong to.

## Overview

| Operation | Method | Path |
|  --- | --- | --- |
| Fetch current user | `GET` | `/api/v3/me` |


There is no request body, no query parameter, and no path parameter. **The access token itself is the input.**

### What it is for

**Credential verification — the "hello world" of Sprinklr integration.** Because `GET /api/v3/me` requires no arguments and touches no business data, it is the cheapest way to prove that a token and API key are valid and correctly paired. If you are debugging a `401` anywhere else in the API, call `/me` first: it isolates the credential from the endpoint. If `/me` returns `200`, your credentials are fine and the problem is elsewhere. If `/me` returns `401`, stop debugging the other endpoint.

This is the recommended first call for any new integration.

**Context discovery.** The response gives you three identifiers you need for most other V3 calls and cannot otherwise derive from a token:

- `id` — the numeric user ID of the authenticated user
- `customerId` — the customer/partner the user belongs to
- `workspaceId` — the workspace the user is operating in


Most V3 endpoints are workspace-scoped. Rather than hard-coding a workspace ID into your configuration, call `/me` once at startup and read it from the response.

**Health check.** As a no-argument `GET`, it is a reasonable liveness probe — with one caveat.

> **The response is not always small.** The `properties` map for a real user can contain hundreds of custom-field entries and is usually the bulk of the payload. If you poll `/me` on a short interval, you are transferring a substantial payload each time. **Poll it sparingly, and cache the identifiers rather than re-fetching them.**


### Relationship to the other user endpoints

| Need | Endpoint |
|  --- | --- |
| Details of **the caller** | **`GET /api/v3/me`** — this page |
| Details of **another user by ID** | `GET /api/v3/user` — V2 equivalent: [Read User](https://dev.sprinklr.com/read-user) |
| Create, update, patch, delete users | `POST` / `PUT` / `PATCH` / `DELETE` on `/api/v3/user` |
| Bulk user operations with job polling | `/api/v3/user/bulk` |


> **This operation is grouped under the `User V3` tag, not a "Me" tag.** If you are looking for it in a generated client or in the API reference, it is filed under **User**.


> **The `/me` response shape is unrelated to the `User` schema.** The `User` schema is a SCIM-style model — `userName`, `schemas`, `photos`, `phoneNumbers`, `emails`, and so on. The `/me` response is a flat shape: `id`, `type`, `name`, `email`, `properties`, `customerId`, `workspaceId`. **Do not reuse a `User`-typed model for `/me`.**


## Base URL

```
https://api3.sprinklr.com/{env}/api/v3/me
```

Replace `{env}` with your assigned environment identifier: `prod`, `prod0`, `prod2`, `prod3`, `prod4`, `prod5`, `prod6`, `prod8`, `prod11`, `prod12`, `prod15`, `prod16`, `prod17`, `prod18`, `prod19`, `prod21`, or `prod25`.

See [APIs | Sprinklr Developer Portal](https://dev.sprinklr.com/apis) for the published environment list. Make the base URL a single configuration value rather than hard-coding the host.

> **Credentials are environment-scoped.** An API key and token generated for one environment return `401` against another, even when the request is otherwise perfect. Because `/me` is the endpoint you will use to *test* credentials, this is worth stating plainly: a `401` from `/me` very often means "right credentials, wrong environment" rather than "bad credentials."


## Authentication

All calls are authenticated with OAuth 2.0. See [API Overview](https://dev.sprinklr.com/api-overview) for portal registration, API key and secret generation, and the Authorize flow.

### Required headers

This is a `GET` with no request body, so there is **no `Content-Type` header**.

| Header | Value | Purpose |
|  --- | --- | --- |
| `Authorization` | `Bearer {{accessToken}}` | Credential used by the API to authenticate a user with the server |
| `Key` | `{{apiKey}}` | API key that authenticates the application with the server. See [API Key and Secret Generation](https://dev.sprinklr.com/api-key-and-secret-generation) |
| `Accept` | `application/json` | Determines the acceptable response type from the server |


**Both `Authorization` and `Key` are required on every call.** Sending only one returns `401`.

### Credential lifetimes

| Credential | Lifetime |
|  --- | --- |
| Authorization code | **10 minutes** |
| API key | No expiry |
| Access token | **30 days by default** |


> **One token pair per API key.** Generating a new access token for an API key invalidates the previously issued token and refresh token for that key. Two services sharing one key will knock each other offline — and because `/me` is your credential-test endpoint, a sudden `401` here is a strong signal that another service has re-issued a token against the same key.


> **Credential hygiene.** Never commit an access token or API key, never paste one into a ticket, and never log the `Authorization` or `Key` header values. Every credential on this page is a placeholder.


> **Treat the `/me` response as PII.** The response contains no credential fields, but it does contain the user's email address and their full custom-property map, which may include personally identifiable or operationally sensitive values such as location, shift, employer, and consent flags. Apply the same logging and storage controls you would to any user record.


## Fetch the current user

```
GET https://api3.sprinklr.com/{env}/api/v3/me
```

The operation takes **no parameters and no request body**. There is nothing to send but headers.

### Example request

```bash
curl -X GET \
  'https://api3.sprinklr.com/{env}/api/v3/me' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Accept: application/json'
```

Because there is nothing to vary, this call is identical for every caller. The only thing that changes the response is **which token you send.**

## The response

### `data` is an array

**V3 returns `data` as an array containing the user object:**

```json
{
  "data": [
    {
      "id": 60000000,
      "type": "PARTNER_ADMIN",
      "name": "Jane Doe",
      "email": "jane.doe@example.com",
      "properties": {
        "spr_user_availability_status": ["Connection Issue"],
        "support_access": ["true"],
        "_c_00000000000000000000000a": ["Morning Shift"]
      },
      "customerId": 60000000,
      "workspaceId": 60000002
    }
  ],
  "errors": []
}
```

*The `properties` map is abridged here. A real response contains many more entries.*

> **This is the one change that breaks a V2 client.** V2 returns `data` as a single object; V3 returns an array. A client doing `response.data.email` gets `undefined` against V3 — silently, with no error. Change it to `response.data[0].email`.


```diff
- const me = response.data;        // V2
+ const me = response.data[0];     // V3
```

```diff
- email = resp["data"]["email"]    # V2
+ email = resp["data"][0]["email"] # V3
```

Guard against an empty array rather than indexing blindly:

```python
data = resp["data"]
if not data:
    raise ValueError("/me returned an empty data array")
me = data[0]
```

### Response fields

| Field | Type | Description |
|  --- | --- | --- |
| `id` | Integer | Numeric user ID of the authenticated user |
| `type` | String | User type — see [The `type` field](#the-type-field) |
| `name` | String | Display name of the user |
| `email` | String | Email address of the user |
| `properties` | Object | Map of custom-field keys to arrays of string values — see [The `properties` map](#the-properties-map) |
| `customerId` | Integer | Identifier of the customer/partner the user belongs to |
| `workspaceId` | Integer | Identifier of the user's workspace |
| `errors` | Array | Sibling of `data`. Empty on success |


The field names are identical to V2. Only the envelope changed.

> **Parse the ID fields as 64-bit integers.** Values vary widely in magnitude between environments. Do not round-trip them through a float, and do not infer a fixed width or format from an example.


### The `properties` map

`properties` is a map of **custom-field key → array of string values**. Three key formats appear:

| Key format | Example | Meaning |
|  --- | --- | --- |
| `_c_` + 24-character hex ID | `_c_00000000000000000000000a` | Custom field, prefixed form — the most common |
| Bare 24-character hex ID | `00000000000000000000000b` | Custom field, unprefixed form |
| Named platform key | `spr_user_availability_status` | Built-in platform property |


**Every value is an array of strings, without exception** — even when the underlying value is a number, a boolean, or a timestamp:

```json
"support_access":                    ["true"],            // boolean as string
"_c_00000000000000000000000c":       ["300"],             // number as string
"_c_00000000000000000000000d":       ["1752172200000"],   // epoch millis as string
"_c_00000000000000000000000e":       ["no", "not match"]  // genuinely multi-valued
```

**Parse accordingly.** Do not assume a scalar. The correct accessor is always "read the array, then take element `0` if you expect one value" — and you must cast the string yourself.

Named platform keys you may see include:

`spr_user_availability_status`, `spr_availability_status_update_time`, `spr_availability_status_updation_reason`, `previous_spr_user_availability_status`, `previous_spr_user_availability_status_update_time`, `spr_previous_availability_status_updation_reason`, `auxiliary_user_availability_status`, `auxiliary_user_availability_status_update_time`, `availability_status_updated_by`, `schedule_adherence_tracking_mode`, `support_access`, `spr_user_is_resource`, `spr_guest_user`, `spr_influencer_user`, `spr_user_automatic_deactivation_period`, `spr_voice_recording_consent_provided`, `spr_screen_recording_consent_provided`, `amazon_connect_quick_connect_id`

These are agent and workforce-management properties — availability status, shift adherence, recording consent, and contact-centre integration. **The set returned varies by user, workspace, and edition.**

Three practical points:

1. **Custom-field keys are environment-specific.** A `_c_<id>` key from one environment will not exist in another. Never hard-code one across environments.
2. **Some values contain HTML.** Rich-text custom fields return markup such as `"<p class=\"export-block__parent\">test</p>"`. Sanitize before rendering.
3. **The map may contain PII and operational data.** Apply appropriate handling.


**Treat `properties` as an opaque, user-specific bag** unless you have confirmed a specific key with your Sprinklr admin.

### The `type` field

`type` tells you what the caller is permitted to do, and it is a reasonable basis for deciding whether your integration should expose administrative functionality.

| User type | Value | Description |
|  --- | --- | --- |
| Partner Admin | `PARTNER_ADMIN` | Highest level of access; has visibility across the entire brand, can manage users, accounts, workflow structures, and client (local division) accesses and structures |
| Partner User | `PARTNER_USER` | Second highest level of access; has visibility across the entire brand but cannot manage client (local division) accesses |
| Client Admin | `CLIENT_ADMIN` | Highest level of access within a Client environment; can manage users, accounts, and workflow structures within their local Client |
| Client User | `CLIENT_USER` | Lowest level of access; cannot manage users or accounts, and cannot manage workflow structures within any local Client environment |


**Always include a default branch when switching on `type`.** New values can be introduced without a version change.

See [User APIs](https://dev.sprinklr.com/user-apis) for more on user types.

## Status codes

| HTTP code | Scenario |
|  --- | --- |
| `200 OK` | Authenticated user returned |
| `400 Bad Request` | Malformed request. Unusual here — there is nothing to malform but headers |
| `401 Unauthorized` | Invalid, missing, or expired `Authorization` token or `Key` header, or credentials from a different environment |
| `403 Forbidden` | Credentials valid but not permitted |
| `404 Not Found` | Wrong path or wrong `{env}` segment |


### The error object

| Field | Type | Description |
|  --- | --- | --- |
| `id` | String | Error identifier |
| `code` | Integer | Numeric error code |
| `message` | String | Error key, for example `account.not.found` |


Error responses return `data` as `null`.

### Troubleshooting

Because `/me` is the endpoint you use to diagnose *other* endpoints, this table is deliberately credential-focused.

| Symptom | Likely cause | Fix |
|  --- | --- | --- |
| `undefined` or `KeyError` reading a field after migrating | `data` is an **array** in V3, an object in V2 | Use `data[0]` |
| `401` with correct-looking credentials | Key and token belong to a **different environment** | Regenerate for the target `{env}` |
| `401` that started suddenly | Token expired (30-day default), **or** a second service issued a new token against the same API key | Refresh; give each service its own key |
| `401` and only one auth header sent | Both `Authorization` and `Key` are required | Send both |
| `401` from another endpoint | Unclear whether it is the credential or the endpoint | **Call `/me` first** to isolate the variable |
| `404` on every call | Wrong `{env}` segment or wrong path | Use `https://api3.sprinklr.com/{env}/api/v3/me` |
| Cast error reading `properties` | **Every** value is an array of strings, even numbers and booleans | Read element `[0]` and cast |
| A `properties` key is missing | Custom-field keys are environment- and user-specific | Never hard-code `_c_*` keys across environments |
| Rendering shows raw HTML tags | Rich-text custom fields return markup | Sanitize before rendering |
| Response much larger than expected | `properties` can hold hundreds of entries | Cache the result; do not poll tightly |
| `type` value not in your switch | New user types can appear | Handle unknown values gracefully |


## Migrating from V2

### The request is unchanged; the response is not

| Element | V2 | V3 | Changed? |
|  --- | --- | --- | --- |
| Method | `GET` | `GET` | No |
| Path | `/api/v2/me` | `/api/v3/me` | **Version segment only** |
| Query / path parameters | None | None | No |
| Request body | None | None | No |
| Headers | `Authorization`, `Key`, `Accept` | Identical | No |
| Response field names | 7 fields | Same 7 fields | No |
| **`data` shape** | **Object** | **Array** | **Yes — breaking** |


### Migration checklist

1. **Change `v2` to `v3`** in the path. Nothing else about the request changes.
2. **Change your response accessor from `data` to `data[0]`.** This is the one thing that will break, and it fails silently — you get `undefined`, not an error. Do this before you deploy.
3. **Guard against an empty array** rather than indexing blindly.
4. **Re-check any `properties` keys you read.** Keys are environment-specific; verify each `_c_*` key in the target environment.
5. **Parse `properties` values as arrays of strings**, casting to number, boolean, or date yourself.
6. **Verify credentials are issued for the target environment** before assuming a code problem.
7. **Use `/me` as your migration smoke test.** It is the cheapest way to confirm V3 credentials work at all before migrating heavier endpoints.


### A version-safe accessor

If you need to support both versions during a phased rollout:

```python
def current_user(resp_json):
    """Return the user object from a v2 or v3 /me response."""
    data = resp_json.get("data")
    if isinstance(data, list):
        if not data:
            raise ValueError("/me returned an empty data array")
        return data[0]          # v3
    return data                 # v2
```

This lets you switch versions by configuration and removes the highest-risk item in the migration.

## Common tasks

### Verify credentials before anything else

```bash
curl -s -o /dev/null -w '%{http_code}\n' \
  'https://api3.sprinklr.com/{env}/api/v3/me' \
  -H 'Authorization: Bearer {{accessToken}}' \
  -H 'Key: {{apiKey}}' \
  -H 'Accept: application/json'
```

`200` means the token, the API key, and the environment all agree. Anything else means the problem is your credentials, not the endpoint you were originally calling.

### Discover the workspace at startup

```python
me = current_user(requests.get(url, headers=headers).json())
WORKSPACE_ID = me["workspaceId"]
CUSTOMER_ID  = me["customerId"]
USER_ID      = me["id"]
```

Cache these for the process lifetime rather than calling `/me` per request.

### Gate administrative features on user type

```python
if me["type"] in ("PARTNER_ADMIN", "CLIENT_ADMIN"):
    enable_admin_features()
else:
    enable_standard_features()   # default branch handles unknown types
```

### Read a custom property safely

```python
def prop(me, key, default=None):
    values = me.get("properties", {}).get(key)
    if not values:
        return default
    return values[0]              # always an array of strings

status = prop(me, "spr_user_availability_status")
```

## Best practices

**Credentials**

- Send both `Authorization` and `Key` on every call.
- Confirm credentials are issued for the environment in your base URL before debugging anything else.
- Give each service its own API key — a second token generation invalidates the first.


**Response handling**

- `data` is an array. Read `data[0]`, and guard against it being empty.
- Parse `id`, `customerId`, and `workspaceId` as 64-bit integers.
- Always inspect the `errors` array, not just the HTTP status.


**Working with `properties`**

- Every value is an array of strings. Read element `[0]` and cast it yourself.
- Custom-field keys are environment-specific — never hard-code a `_c_*` key across environments.
- Sanitize rich-text values before rendering.
- Treat the whole map as PII.


**Operations**

- Cache the identifiers rather than polling. The response can be large.
- Use `/me` as your integration smoke test and as the first step in any `401` investigation.
- Handle unknown `type` values with a default branch.


## Related

- [Me Api (V2)](https://dev.sprinklr.com/me-api)
- [User APIs](https://dev.sprinklr.com/user-apis)
- [SCIM (User) APIs](https://dev.sprinklr.com/scim-user-apis)
- [Read User](https://dev.sprinklr.com/read-user)
- [API Overview](https://dev.sprinklr.com/api-overview)