---
key: api-conventions
title: Paging, filtering, errors and rate limits
audience: developer
section: api/getting-started
routes: []
since: 0.0.1
updated: 0.0.1
status: published
summary: The conventions every Nova operation follows for lists, record identity, updates, the error envelope, idempotency and rate limits.
keywords: [pagination, filters, errors, rate limit, idempotency, conventions, page_size]
related: [api-overview, api-errors, api-limits, api-record-identity, api-reference]
---

These rules hold for every operation, whether it is in the documented
[[api-reference]] or only in the operation index ([[find-what-to-call]]).

## Lists

List operations take `page` and `page_size` (and sometimes `sort_by` /
`sort_order`); most also take a free-text `query` (or `q`) that matches what
the app's own search box matches. The reference lists each operation's
filters. Ask for what you need: large pages are slower and count against the
same rate limit.

```bash
curl -s "https://app.novabmp.com/v1/crm/accounts/?query=smith&page=1&page_size=25" \
  -H "Authorization: Bearer $NOVA_KEY"
```

## Records

- Address a record by its `uid`, never by a number. See [[api-record-identity]].
- A uid of the wrong type returns `404`, the same as a record that does not
  exist, so a mistyped uid and a missing record look alike.
- Email draft attachment inputs accept File UIDs returned by uploads. Keep
  those references unchanged when saving a draft. Draft body responses include
  `attachment_file_uids` and authorized `attachment_files` entries containing
  `uid`, `original_filename`, `content_type` and `size_bytes`, so a reopened
  attachment retains its display and preview information.
- Updates send only the fields you change. Unknown fields are refused with
  `422` naming the field.
- Archiving hides a record; nothing is deleted. An archived account can still
  be read in full; changing it answers `409 account_archived` until someone
  restores it.

## The error envelope

Every error has the same outer shape. Switch on `error.code`; show
`error.message`; quote `error.request_id` if you contact support.

```json
{
  "error": {
    "code": "account_archived",
    "message": "This account is archived. Restore it to make changes.",
    "request_id": "0f5c1d2e-…",
    "details": {"cta": {"kind": "restore_account"}}
  },
  "detail": "This account is archived. Restore it to make changes."
}
```

Some refusals carry their specific reason inside `detail` rather than in
`error.code` (which then reads `forbidden`). [[api-errors]] lists every code,
where to find it and what to do about it.

## Idempotency

Operations that list an `Idempotency-Key` header in the reference (creating
and updating accounts, contacts, locations, quotes, invoices, tasks,
recording a payment, among others) replay the first response when the same
key comes back, so a retried request never makes a duplicate. Sending the
same key with a different body answers `409 idempotency_payload_mismatch`.

```bash
curl -s -X POST https://app.novabmp.com/v1/tasks \
  -H "Authorization: Bearer $NOVA_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1e0c7a-5d2b-4e8f-9a31-2c7b8d4e0f11" \
  -d '{"title": "Call Smith about the furnace filter"}'
```

Where an operation does not take the header, search before you create and
keep the `uid` you get back, so a retry updates instead of duplicating.

## Rate limits

Each credential has a per-minute limit, the organization has one across all
its software, and an organization can give a credential a daily cap on
changes. Going over answers `429 rate_limit_exceeded` with
`error.details.retry_after_seconds`. Wait that long; never retry in a tight
loop. Numbers and the daily cap are in [[api-limits]].

## Versioning

The documented tier carries the release id in the reference document's
`info.version`. Fields are added, never silently removed; a removal is
announced in the release notes first.

## Email list views and deletion

Mailbox and unified email message lists accept `filters.view` as `messages` or `threads`. In Threads, grouping happens before cursor pagination. Each row carries the authorized matching message UIDs, message count, unread count and attachment indicator for that conversation. Drafts remain separate rows. Read a conversation's message list to retrieve its earlier messages; their bodies and attachments load through the normal authorized endpoints.

Ordinary email deletion uses the message action `trash: true` and moves the message to Deleted Items. `delete_forever: true` is allowed only after that move; otherwise the action returns `email_message_not_in_deleted_items` without deleting anything. Batch actions return opaque message UIDs in their results. Emptying a folder takes its opaque folder UID and requires the folder deletion permission.

## Editing a scheduled customer notification

Read `GET /v1/customer-notifications/{notification_uid}/preview`, then send `PUT /v1/customer-notifications/{notification_uid}` with the returned `revision`, `recipient_address`, `subject_line`, `body_text`, and a future timezone-aware `at`. The opaque notification UID identifies one occurrence throughout scheduling and delivery. Read `editable_fields` and `can_edit` before offering edits. Editing requires `customer_notifications.operate`. Engine operations also require the automations entitlement; log reads remain available independently of that entitlement. Signing reminders also require signer management and signing resend permissions.

A stale revision or an already-claimed send returns 409 without saving changes. Invalid addresses, empty wording, and past or timezone-free send times return validation errors. A save does not send the message, change the customer's contact methods, or bypass consent, delivery limits or quiet hours. Sent entries remain read-only.

Customer notification lists support cursor pagination, record and customer filters, delivery state, channel, source, attention, and date ranges (`date_from`, `date_to`, `time_zone`). `/health` reports processing health; `/export` requires the export permission. `POST /v1/customer-notifications/{notification_uid}/operate` takes `revision` and `action` (`send_now`, `retry`, `resend`); resend requires its own permission. Operations retain domain delivery checks. The platform equivalents are read-only.
