---
source_url: https://www.pubnub.com/docs/general/data-sync/data-operations
title: Working with DataSync data
updated_at: 2026-09-08T16:52:30.000Z
---

# Working with DataSync data

## Documentation index

To discover more PubNub resources:

1. Fetch [PubNub's llms.txt](https://www.pubnub.com/llms-full.txt) for a list of available pages in Markdown format.
2. Identify relevant URLs from that index.
3. Fetch the target pages.

Do not assume a path exists, always check the index first.

Every DataSync resource, entities, relationships, users, channels, and memberships, supports the same operation set:

* list
* get
* create
* replace
* partial update
* delete

All of these operations require Access Manager authorization. Refer to [Access control](https://www.pubnub.com/docs/general/data-sync/access-control.md) for how that works.

###### Every operation is authorized

Access Manager governs every read and write covered on this page. See [Access control](https://www.pubnub.com/docs/general/data-sync/access-control.md).

Every operation below maps to a Core REST API endpoint. Use this table to jump to the request and response reference for any object kind:

|  | Entity | Relationship | User | Channel | Membership |
| --- | --- | --- | --- | --- | --- |
| List | [Get entities](https://www.pubnub.com/docs/sdks/rest-api/get-entities.md) | [Get relationships](https://www.pubnub.com/docs/sdks/rest-api/get-relationships.md) | [Get users](https://www.pubnub.com/docs/sdks/rest-api/get-users.md) | [Get channels](https://www.pubnub.com/docs/sdks/rest-api/get-channels.md) | [Get memberships](https://www.pubnub.com/docs/sdks/rest-api/get-memberships.md) |
| Get | [Get entity](https://www.pubnub.com/docs/sdks/rest-api/get-entity.md) | [Get relationship](https://www.pubnub.com/docs/sdks/rest-api/get-relationship.md) | [Get user](https://www.pubnub.com/docs/sdks/rest-api/get-user.md) | [Get channel](https://www.pubnub.com/docs/sdks/rest-api/get-channel.md) | [Get membership](https://www.pubnub.com/docs/sdks/rest-api/get-membership.md) |
| Create | [Create entity](https://www.pubnub.com/docs/sdks/rest-api/create-entity.md) | [Create relationship](https://www.pubnub.com/docs/sdks/rest-api/create-relationship.md) | [Create user](https://www.pubnub.com/docs/sdks/rest-api/create-user.md) | [Create channel](https://www.pubnub.com/docs/sdks/rest-api/create-channel.md) | [Create membership](https://www.pubnub.com/docs/sdks/rest-api/create-membership.md) |
| Replace | [Update entity](https://www.pubnub.com/docs/sdks/rest-api/update-entity.md) | [Update relationship](https://www.pubnub.com/docs/sdks/rest-api/update-relationship.md) | [Update user](https://www.pubnub.com/docs/sdks/rest-api/update-user.md) | [Update channel](https://www.pubnub.com/docs/sdks/rest-api/update-channel.md) | [Update membership](https://www.pubnub.com/docs/sdks/rest-api/update-membership.md) |
| Partial update | [Patch entity](https://www.pubnub.com/docs/sdks/rest-api/patch-entity.md) | [Patch relationship](https://www.pubnub.com/docs/sdks/rest-api/patch-relationship.md) | [Patch user](https://www.pubnub.com/docs/sdks/rest-api/patch-user.md) | [Patch channel](https://www.pubnub.com/docs/sdks/rest-api/patch-channel.md) | [Patch membership](https://www.pubnub.com/docs/sdks/rest-api/patch-membership.md) |
| Delete | [Delete entity](https://www.pubnub.com/docs/sdks/rest-api/delete-entity.md) | [Delete relationship](https://www.pubnub.com/docs/sdks/rest-api/delete-relationship.md) | [Delete user](https://www.pubnub.com/docs/sdks/rest-api/delete-user.md) | [Delete channel](https://www.pubnub.com/docs/sdks/rest-api/delete-channel.md) | [Delete membership](https://www.pubnub.com/docs/sdks/rest-api/delete-membership.md) |

## Creating objects

Every create names the class the new object is an instance of, and what else you must supply depends on the object kind:

| Creating | You must supply |
| --- | --- |
| An entity | The class name and class version |
| A relationship | Both linked entity ids, the class name, and the class version |
| A user | The class version. The class name defaults to `User` |
| A channel | The class version. The class name defaults to `Channel` |
| A membership | `channelId`, `userId`, and the class version |

Users, channels, and memberships can infer their class because they're built on built-in classes, which is why they need only a version. Generic entities and relationships have no default class, so they name one explicitly.

Beyond that, you can optionally supply your own `id` and a `status`, plus the payload itself. If you don't supply an `id`, the server generates one. Supplying an `id` that already exists is rejected with a `409 Conflict`.

DataSync doesn't validate the payload against a JSON Schema. Write-time validation is limited to the properties you declare on the class: a value whose type doesn't match the declared `valueKind` is rejected with a `400`, as is a missing value for a non-nullable property. Fields you haven't declared are stored as-is.

Request bodies are wrapped in a `data` object, and writes take a versioned vendor media type. In [Bob's marketplace](https://www.pubnub.com/docs/general/data-sync/overview.md#running-example-bobs-live-marketplace), creating `product-sneaker-42` means naming the `Product` class at version 1:

```http
POST /v1/datasync/subkeys/{subKey}/entities?auth=<token>
Content-Type: application/vnd.pubnub.objects.entity+json;version=1

{
  "data": {
    "id": "product-sneaker-42",
    "entityClass": "Product",
    "entityClassVersion": 1,
    "status": "active",
    "payload": { "name": "Retro Sneaker", "price": 89.99, "stock": 12 }
  }
}
```

An unsupported `Content-Type` is rejected with a `415`, and an `Accept` header DataSync can't satisfy with a `406`.

### JavaScript

```javascript
const response = await pubnub.dataSync.createEntity({
    id: 'product-sneaker-42',
    class: 'product',
    data: {
        classVersion: 1,
        payload: { name: 'Retro Sneaker', price: 89.99, stock: 12 },
    },
})
```

### C#

```csharp
PNResult<PNDataSyncEntityResult> response = await pubnub.DataSync.CreateEntity(new CreateEntityParameters
{
    Id = "product-sneaker-42",
    EntityClass = "product",
    EntityClassVersion = 1,
    Payload = new Dictionary<string, object>
    {
        { "name", "Retro Sneaker" },
        { "price", 89.99 },
        { "stock", 12 },
    },
});
```

### curl

```bash
curl -X POST 'https://ps.pndsn.com/v1/datasync/subkeys/{subKey}/entities?auth=<token>' \
  -H 'Content-Type: application/vnd.pubnub.objects.entity+json;version=1' \
  -d '{
    "data": {
      "id": "product-sneaker-42",
      "entityClass": "product",
      "entityClassVersion": 1,
      "payload": { "name": "Retro Sneaker", "price": 89.99, "stock": 12 }
    }
  }'
```

Refer to [Create entity (JavaScript)](https://www.pubnub.com/docs/sdks/javascript/api-reference/data-sync.md#create-entity), [Create entity (C#)](https://www.pubnub.com/docs/sdks/c-sharp/api-reference/data-sync.md#create-entity), and [Create entity (REST)](https://www.pubnub.com/docs/sdks/rest-api/create-entity.md) for the full parameter reference.

## Reading objects

Getting an object by ID returns its system fields and its payload. Refer to [Get entity](https://www.pubnub.com/docs/sdks/rest-api/get-entity.md) for the request and response reference, or to the endpoint table at the top of this page for the other object kinds. Projection filtering applies to `payload` and `status` only: the remaining system fields are always returned in full. For more information, refer to [Projections](https://www.pubnub.com/docs/general/data-sync/projections.md).

A class that declares no `/status` property treats `status` as belonging to `__default__` alone, so a read under a named projection drops it. To expose `status` to a named projection, declare a `/status` property tagged with that projection.

Expired objects are not returned by reads. Eventually consistent search (`filter`) can currently still return an object whose `expiresAt` has passed, so check `expiresAt` on results from that tier. For more information, refer to [Data expiry (TTL)](https://www.pubnub.com/docs/general/data-sync/schemas-and-validation.md#data-expiry-ttl).

## Updating objects

DataSync supports two ways to update an object:

* [replace](#replace)
* [partial update](#partial-update)

### Replace

Replace is a `PUT`. Refer to [Update entity](https://www.pubnub.com/docs/sdks/rest-api/update-entity.md), [Update relationship](https://www.pubnub.com/docs/sdks/rest-api/update-relationship.md), [Update user](https://www.pubnub.com/docs/sdks/rest-api/update-user.md), [Update channel](https://www.pubnub.com/docs/sdks/rest-api/update-channel.md), or [Update membership](https://www.pubnub.com/docs/sdks/rest-api/update-membership.md) for the request and response reference.

Replace sends the new state for every payload field visible within the token's resolved projection, including the class version. Payload fields outside that projection are left untouched, not wiped and not required in the request body. The top-level `status` field has additional behavior described below.

For a class with no custom projections, where every field is in `__default__`, replace behaves exactly like sending the full object.

In [Bob's marketplace](https://www.pubnub.com/docs/general/data-sync/overview.md#running-example-bobs-live-marketplace), `user-alice` has `display_name` and `avatar_url` in both `__default__` and `admin` projections, and `email` and `phone` in `admin` only, as described in [Projections](https://www.pubnub.com/docs/general/data-sync/projections.md).

A token holding only `__default__` can replace `user-alice` by sending just `display_name` and `avatar_url`. It doesn't need to know about or supply `email` and `phone`, and their values are left exactly as they were. A token holding `admin` can replace all four fields. Naming a field outside the token's resolved projection is rejected with a `403`.

Two things to watch in a replace body:

* The class version isn't a passive echo. Sending a different existing version of the same class re-points the object at that version. A version whose base Global class differs from the object's own is rejected with a `400`, so a user can't be turned into a channel.
* `status` is protected by its declared projections. If the resolved projection includes `/status`, omitting `status` from a replace body sets it to null. If the resolved projection excludes `/status`, changing it is rejected with a `403`. In the current service implementation, omission is also treated as a change when the stored status is non-null, so that replace is rejected rather than preserving the hidden value.

A replace reaches only the fields in the token's projection. Everything outside it stays as it was, so a `__default__` replace does not wipe the `admin`-only fields:

### Partial update

Partial update is a `PATCH`. Refer to [Patch entity](https://www.pubnub.com/docs/sdks/rest-api/patch-entity.md), [Patch relationship](https://www.pubnub.com/docs/sdks/rest-api/patch-relationship.md), [Patch user](https://www.pubnub.com/docs/sdks/rest-api/patch-user.md), [Patch channel](https://www.pubnub.com/docs/sdks/rest-api/patch-channel.md), or [Patch membership](https://www.pubnub.com/docs/sdks/rest-api/patch-membership.md) for the request and response reference.

Partial update uses JSON Patch (RFC 6902) with `add`, `remove`, `replace`, `move`, `copy`, and `test` operations, addressed by JSON Pointer paths into the object. A pointer starts at the object, where `payload` is one field alongside the system fields, so the price on a product is `/payload/price`.

A price change on `product-sneaker-42` looks like this:

```http
PATCH /v1/datasync/subkeys/{subKey}/entities/product-sneaker-42?auth=<token>
Content-Type: application/json-patch+json
If-Match: 1f0zq2h

[{ "op": "replace", "path": "/payload/price", "value": 79.99 }]
```

The patch document is a bare array rather than a body wrapped in `data`, it needs the `application/json-patch+json` content type, and it must contain at least one operation.

### Which fields an update can address

A partial update can only address three paths on the object:

* `/status`
* `/entityClassVersion`, or `/relationshipClassVersion` for relationships and memberships
* `/payload`, or anything beneath it

Any other pointer, including `/id`, `/entityClass`, `/entityClassLevel`, `/createdAt`, `/updatedAt`, `/expiresAt`, `/eTag`, and for relationships `/entityAId`, `/entityBId`, and `/relationshipClass`, is rejected with a `400 Bad Request`, and the error lists the paths you can modify.

`test` is the one exception to this restriction: it can target any pointer, including the otherwise restricted system fields, because it never modifies the document. That makes it a way to assert `/eTag` inline as part of the patch, instead of relying on `If-Match`.

A replace body has no fields for `id`, the class name, the class level, or the linked entity ids. Sending them anyway isn't an error: they're ignored, and the request returns `200 OK` with the object unchanged in those respects.

:::note Memberships
Memberships support both replace and partial update. The same projection rules described above apply to both: a replace is scoped to the token's resolved projection, and fields outside that projection are left untouched.
:::

## Optimistic concurrency with ETags

Every entity and relationship carries an `eTag` that changes on every write. It's returned in the response body as `data.eTag`, and it's an opaque token, so send it back exactly as you received it, with no surrounding quotes.

`If-Match` is a request header on every write endpoint, documented per endpoint, for example on [Patch entity](https://www.pubnub.com/docs/sdks/rest-api/patch-entity.md).

`If-Match` is optional. Omit it and the write applies unconditionally. Send the `eTag` you last read as `If-Match` to make the write conditional, or `If-Match: *` to require only that the object still exists. If the value no longer matches the object's current `eTag`, the write is rejected with a `412 Precondition Failed` instead of silently overwriting someone else's change.

The pattern is:

1. read
2. modify
3. write with `If-Match`
4. if `412`, re-read and retry

In Bob's marketplace, two staff members both adjust the stock count on `product-sneaker-42` around the same time. Both read the object and get the same `eTag`. The first write succeeds and changes the `eTag`. The second write, still carrying the old `eTag`, gets a 412 instead of overwriting the first change. The second staff member re-reads the updated stock count and applies their adjustment on top of it.

:::tip Combine ETags with events
If you're also subscribed to an object's [events](https://www.pubnub.com/docs/general/data-sync/events.md), use an incoming event as a signal to refresh your copy of the object (and its `eTag`) before you write, rather than writing.
:::

###### Stay current without re-querying

Optimistic concurrency and search complement real-time delivery. Read an object's state once, then rely on events to keep it current instead of re-fetching. See [Events](https://www.pubnub.com/docs/general/data-sync/events.md).

## Deleting objects and expiry

Delete removes an object immediately from reads. Like other writes, delete respects `If-Match`, so a delete against a stale `eTag` is rejected with a 412. Deleting an entity also deletes every relationship linked to it.

Refer to [Delete entity](https://www.pubnub.com/docs/sdks/rest-api/delete-entity.md), [Delete relationship](https://www.pubnub.com/docs/sdks/rest-api/delete-relationship.md), [Delete user](https://www.pubnub.com/docs/sdks/rest-api/delete-user.md), [Delete channel](https://www.pubnub.com/docs/sdks/rest-api/delete-channel.md), or [Delete membership](https://www.pubnub.com/docs/sdks/rest-api/delete-membership.md) for the request and response reference.

A successful delete returns `200 OK` with an empty body. Deleting an ID that doesn't exist returns a `404`, so delete isn't idempotent. If you supply `If-Match` against an object that isn't there, you get a `412` rather than a `404`.

In Bob's marketplace, deleting `product-sneaker-42` deletes its `ProductOwner` relationship to `seller-bob` along with it. The relationships that get deleted, and therefore the linked-entity channels their delete events reach, are the ones that existed immediately before the entity was deleted. Refer to [Where events are published](https://www.pubnub.com/docs/general/data-sync/events.md#where-events-are-published) for how a delete's event routing follows from this.

The cascade removes the linked relationships, but not the entities on the other end. Deleting `product-sneaker-42` removes the `ProductOwner` link, while `seller-bob` stays:

Objects also expire automatically based on their class TTL. In short: `expiresAt` is set once at creation and is not refreshed by updates, and a relationship expires at the earlier of its two linked entities' expiry times. See the [Data expiry (TTL) section on Schemas and validation](https://www.pubnub.com/docs/general/data-sync/schemas-and-validation.md#data-expiry-ttl) for the full model.

## Finding data

In DataSync, you can find and browse through data by:

* [Filtering](#filtering)
* [Sorting and pagination](#sorting-and-pagination)

The list endpoints are [Get entities](https://www.pubnub.com/docs/sdks/rest-api/get-entities.md), [Get relationships](https://www.pubnub.com/docs/sdks/rest-api/get-relationships.md), [Get users](https://www.pubnub.com/docs/sdks/rest-api/get-users.md), [Get channels](https://www.pubnub.com/docs/sdks/rest-api/get-channels.md), and [Get memberships](https://www.pubnub.com/docs/sdks/rest-api/get-memberships.md). Each documents the `filter_fast`, `filter`, `sort`, `cursor`, and `limit` query parameters described below.

Listing generic entities requires an `entity_class`, and listing generic relationships requires a `relationship_class`. There's no way to list every entity on a keyset regardless of class, and omitting the parameter is rejected with a `400`. User, channel, and membership lists have no required parameter. To find the class names available on your keyset, list them with [Get all entity class entries](https://www.pubnub.com/docs/admin-api/get-all-entity-class-entries.md) or [Get all relationship classes](https://www.pubnub.com/docs/admin-api/get-all-relationship-classes.md).

Add `entity_class_level` (`Global` or `SubKey`) to disambiguate a keyset-level class from a Global class of the same name. Omit it and the keyset-level class wins.

Add `entity_class_version` (or `relationship_class_version` for relationships) to match only that version. Omit it to list instances across every version of the class, not just the latest one.

### Filtering

DataSync offers two mutually exclusive filtering parameters: `filter_fast` for strongly consistent queries and `filter` for eventually consistent queries. Supplying both in one request is rejected with a `400`.

|  | Strongly consistent (`filter_fast`) | Eventually consistent (`filter`) |
| --- | --- | --- |
| Runs against | Properties declared with filtering mode `simple` or `full` | Properties declared with filtering mode `full` |
| Storage | The same storage used for writes | A separate search store |
| Consistency | Strongly consistent; reflects completed writes | Eventually consistent; can briefly lag recent writes |
| Predicate count | Maximum 10 predicates per expression currently | Not currently enforced |

Both parameters share the same expression language, so switching between them doesn't mean rewriting your expression. The difference is which store answers the query, which properties are eligible, how fresh the results are, and the current predicate limit.

| Operators |  |
| --- | --- |
| Comparison | `==`, `!=`, `<`, `>`, `<=`, `>=` |
| Pattern matching | `LIKE` (case-insensitive), `SLIKE` (case-sensitive), `ILIKE` (case-insensitive, same as `LIKE`) |
| Logical | `&&`, `||`, `!`, and parentheses for grouping |

Values can be strings in single or double quotes, numbers, `true`, `false`, or `null`. Recognized string escapes are `\n`, `\t`, `\r`, `\\`, `\"`, and `\'`, and `\uXXXX` isn't supported. Compare a `date` or `datetime` property against a quoted ISO-8601 string (`"2026-08-14"` for a `date`, `"2026-08-14T00:00:00Z"` for a `datetime`), and a malformed value is a `400`. Property names are flat identifiers, so dotted paths like `custom.public` aren't supported.

`null` is the one value you can compare against a property of any type, but only with `==` and `!=`. Pairing `null` with an ordering operator (`<`, `>`, `<=`, `>=`) or a pattern operator (`LIKE`, `SLIKE`, `ILIKE`) is rejected with a `400`.

Operator keywords and literals are case-insensitive, so `like`, `Slike`, `true`, and `null` all parse. A single `=` is not accepted as an equality operator.

In `LIKE`, `SLIKE`, and `ILIKE` patterns, `*` matches any sequence of characters. `%` and `_` are literal. The eventually consistent `filter` parameter additionally treats `?` as a single-character wildcard. There's currently no way to match a literal `*`.

:::note
LIKE
is case-insensitive here
Unlike SQL, DataSync's `LIKE` ignores case. Use `SLIKE` when you need a case-sensitive match.
:::

Pattern operators apply to `string` properties only, and the ordering operators (`<`, `>`, `<=`, `>=`) don't apply to `boolean` properties. Comparing a property to a value of the wrong type, a `number` property to a string for instance, is rejected with a `400`. You filter on a property's `name`, and beyond the [built-in fields](#built-in-fields) only properties declared on the class are filterable.

In Bob's marketplace, `filter_fast` could find every `Product` with `price < 100` and immediately reflect a completed write. `filter` could find products whose name matches a broader pattern, useful for a more search-like lookup across a larger catalog, while tolerating a short delay before a recent write appears in results.

Querying a parent entity class also matches instances of its subclasses. Relationship and membership lists match only the named relationship class, across its versions, with no descendant walk. Refer to [Class inheritance on Schemas and validation](https://www.pubnub.com/docs/general/data-sync/schemas-and-validation.md#class-inheritance).

:::warning Declare filterable properties first
Beyond the [built-in fields](#built-in-fields), filtering only works on properties you've declared on the class, and only for data written after the property was declared. Data written earlier isn't retroactively indexed. See [Property definitions](https://www.pubnub.com/docs/general/data-sync/schemas-and-validation.md#property-definitions).
:::

#### Built-in fields

Four fields every object carries natively are filterable and sortable without being declared on the class:

| Field | Filters as |
| --- | --- |
| `id` | `string` |
| `createdAt` | `datetime` |
| `updatedAt` | `datetime` |
| `status` | `string` |

They work in both tiers and on a class that declares no properties at all, so `status == "active"` runs under `filter_fast`, `createdAt > "2026-08-01T00:00:00Z"` runs under `filter`, and `sort=createdAt:desc` orders by either. Compare `createdAt` and `updatedAt` against a quoted ISO-8601 datetime.

Because they're built in, these four names are reserved. A class property can't be named `id`, `createdAt`, or `updatedAt`, and `status` may only be declared as `{"name": "status", "path": "/status"}` to put the native field in a projection. Anything else is rejected with a `400` (`DS-0906`). Refer to [Property definitions](https://www.pubnub.com/docs/general/data-sync/schemas-and-validation.md#property-definitions).

`expiresAt` and `eTag` are not in this set. Neither can be filtered or sorted on.

:::note
Declaring
status
can hide it from filters
If a class declares `/status` and scopes it to a named projection, a request whose token can't reach that projection loses `status` as a filter and sort target, because a list query can't resolve a single object's projection up front. A `status` you never declared stays filterable for every token. Refer to [Projections](https://www.pubnub.com/docs/general/data-sync/projections.md).
:::

###### Declared properties power search

Apart from the four built-in fields, both `filter_fast` and `filter` only work on properties you declare on a class. Refer to [Schemas and validation](https://www.pubnub.com/docs/general/data-sync/schemas-and-validation.md).

### Sorting and pagination

List endpoints accept a `sort` parameter: a comma-separated list of property names, each optionally followed by `:desc` for descending order, for example `price:desc` or `name,price:desc`.

A property with no suffix sorts ascending. Only `:desc` and `:descending` mean descending, and they're matched case-insensitively. Any other suffix, `:asc` included, sorts ascending without reporting an error, and a leading `-` isn't a descending marker, so `-price` is read as a property name and rejected with a `400`.

You sort by a property's `name`, not its `path`. Beyond the [built-in fields](#built-in-fields) `id`, `createdAt`, `updatedAt`, and `status`, only declared properties are sortable.

Which properties are sortable depends on the filtering tier the request uses, because sorting runs in whichever store the query runs against:

| Request | Sortable properties |
| --- | --- |
| No filter, or `filter_fast` | `filtering` mode `simple` or `full`, plus the built-in fields |
| `filter` | `filtering` mode `full` only, plus the built-in fields |

The consequence worth planning for: a `simple` property that sorts fine on its own is rejected when you combine it with `filter`. If you need to use eventually consistent filtering and sorting in one query, declare both properties as `full`.

Sorting by a property that isn't sortable in that context is rejected with a 400, and the error names the properties you can sort by. If you omit `sort`, results come back in a stable order by `id`. When you do sort, nulls sort last in both directions.

List endpoints use cursor-based pagination. Page size ranges from 1 to 100, with a default of 20. Pagination is forward-only, there is no cursor for a previous page, and there is no total count. An invalid cursor is rejected with a `400`.

Membership lists additionally accept `user_id` and `channel_id` to narrow results, both documented on [Get memberships](https://www.pubnub.com/docs/sdks/rest-api/get-memberships.md). Both are optional and combine as an AND. They narrow results on the strongly consistent tier only: combining `user_id` or `channel_id` with `filter` currently ignores them and searches across all memberships.

In Bob's marketplace, listing `product` entities under `$100`, sorted by price descending, filters strongly consistently and paginates in one call:

#### JavaScript

```javascript
const response = await pubnub.dataSync.getEntities({
    entityClass: 'product',
    filterFast: 'price < 100',
    sort: { price: 'desc' },
    limit: 20,
})
console.log(response.data)
console.log(response.meta)
```

#### C#

```csharp
PNResult<PNDataSyncEntitiesListResult> response = await pubnub.DataSync.GetEntities(new GetEntitiesParameters
{
    EntityClass = "product",
    FilterFast = "price < 100",
    Sort = "price:desc",
    Limit = 20,
});
```

#### curl

```bash
curl -G 'https://ps.pndsn.com/v1/datasync/subkeys/{subKey}/entities' \
  --data-urlencode 'entity_class=product' \
  --data-urlencode 'filter_fast=price < 100' \
  --data-urlencode 'sort=price:desc' \
  --data-urlencode 'limit=20' \
  --data-urlencode 'auth=<token>'
```

To page forward, pass the response's `next_cursor` back as `cursor` on the next call, and stop when `has_next` is `false`. Refer to [Get all entities (JavaScript)](https://www.pubnub.com/docs/sdks/javascript/api-reference/data-sync.md#get-all-entities), [Get all entities (C#)](https://www.pubnub.com/docs/sdks/c-sharp/api-reference/data-sync.md#get-all-entities), and [Get entities (REST)](https://www.pubnub.com/docs/sdks/rest-api/get-entities.md) for the full parameter reference, including the equivalent list methods for users, channels, memberships, and relationships.

## Terms in this document

* **Access Manager** - A cryptographic, token-based permission administrator that allows you to regulate clients' access to PubNub resources, such as channels, channel groups, and user IDs.
* **Channel** - A pathway for sending and receiving messages between devices, created automatically when you first use it, that can handle any number of users and messages for different communication needs, like 1-1 text chats, group conversations, and other data streaming.
* **Class** - A versioned type definition (name plus integer version) for entities or relationships in DataSync. Classes carry property definitions that declare which payload fields are validated, filterable, and scoped by projections.
* **Membership** - A relationship in DataSync that links a channel to a user, using the built-in many-to-many Membership class.
* **Projection** - A named view over an object's payload fields in DataSync, controlling which fields a client can read and write based on its Access Manager token.
* **Relationship** - A typed link between two entities in DataSync, with its own payload and system fields, typed by a relationship class that declares cardinality.
* **User** - An individual or entity that interacts with a system, application, or service. In PubNub, a user typically refers to someone who sends or receives messages through the platform, identified by a unique user ID or username.

Last updated at: 2026-09-08T16:52:30.000Z
