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

# Records (CRUD)

> listRecords, getRecord, createRecord, updateRecord, and deleteRecord — the core Data API operations.

All CRUD methods accept an optional `AbortSignal` as their last parameter. See [Cancellation & Cleanup](/app-builder/sdk/cancellation-and-cleanup) for cancellation patterns.

## listRecords(entityKey, options?, signal?)

Fetches a page of records with optional filtering and sorting.

```javascript theme={null}
const result = await sdk.listRecords('tasks', {
  filter: { status: { eq: 'open' } },
  sort: 'due_date:asc',
  pageSize: 25,
  cursor: undefined,       // omit on first page; pass meta.cursor for subsequent pages
});

// result.data   — RecordData[]
// result.meta   — { hasMore: boolean, cursor: string|null, total?: number }
```

**Options:**

| Option     | Type          | Default | Description                                 |
| ---------- | ------------- | ------- | ------------------------------------------- |
| `filter`   | Filter object | —       | See [Filtering](/app-builder/sdk/filtering) |
| `sort`     | string        | —       | `"fieldKey:asc"` or `"fieldKey:desc"`       |
| `pageSize` | number        | 25      | Records per page (max 100)                  |
| `cursor`   | string        | —       | Pagination cursor from previous response    |

See [Pagination](/app-builder/sdk/pagination) for cursor-based pagination patterns.

## getRecord(entityKey, id, signal?)

Fetches a single record by ID.

```javascript theme={null}
const result = await sdk.getRecord('tasks', '01JA...'); // record id (ULID)
// result.data — RecordData (with id, timestamps, and all field values)
```

## createRecord(entityKey, data, signal?)

Creates a new record. Returns the created record including its assigned `id` and system timestamps.

```javascript theme={null}
const result = await sdk.createRecord('tasks', {
  title: 'Buy milk',
  status: 'open',
  due_date: '2026-04-01',
});
// result.data — RecordData (includes id, created_at, etc.)
```

**Rules:**

* Do not include system fields (`id`, `created_by`, `updated_by`, `created_at`, `updated_at`) — they are set automatically.
* Required fields must be present. Missing required fields throw `ErrorCode.ValidationFailed`.

## updateRecord(entityKey, id, data, signal?)

Partially updates a record. Only the fields you include are changed — omitted fields are untouched.

```javascript theme={null}
const result = await sdk.updateRecord('tasks', '01JA...', {
  status: 'done',
});
// result.data — full updated RecordData
```

**To clear an optional field**, send `null`:

```javascript theme={null}
await sdk.updateRecord('tasks', '01JA...', {
  due_date: null,   // clears the field
});
```

## deleteRecord(entityKey, id, signal?)

Deletes a record. Returns `void` (no response body).

<Warning>Deleted records are permanently removed — they cannot be retrieved, listed, or restored via the SDK.</Warning>

```javascript theme={null}
await sdk.deleteRecord('tasks', '01JA...');
```

## Record Shape

Every record includes these system fields in addition to your schema fields:

| Field        | Type            | Description                      |
| ------------ | --------------- | -------------------------------- |
| `id`         | string (ULID)   | Unique record ID                 |
| `created_by` | string (ULID)   | User who created the record      |
| `updated_by` | string (ULID)   | User who last updated the record |
| `created_at` | ISO 8601 string | Creation timestamp               |
| `updated_at` | ISO 8601 string | Last update timestamp            |

Never include system fields in create or update payloads.
