Pagination

Mailrith uses cursor pagination across list endpoints. This guide explains how to request the first page, continue with `next_cursor`, resume interrupted syncs, and reuse the same pagination pattern across subscribers, tags, custom fields, forms, and segments.

6 min read

Use Cursor Pagination

Mailrith uses cursor pagination for list endpoints. Each API response gives your integration the cursor to use for the next page, so your integration does not need to guess a page number.

Cursor pagination is important when records change while your integration is reading a workspace. Subscribers, tags, forms, landing pages, and segments can be added during a sync. The cursor gives your integration a stable next request even when the total record count changes.

To request the first page, omit starting_after. If the API response sets has_more to true, copy next_cursor into the next request as starting_after. Keep requesting pages until has_more is false.

  1. Send the first list request with a limit and without a starting_after value.
  2. Process every item in the returned data array before requesting the next page.
  3. Read the pagination object in the API response.
  4. If has_more is false, stop the pagination loop.
  5. If has_more is true, store next_cursor and send the next request with starting_after=<next_cursor>.
  6. After each page is fully processed, write your progress so a scheduled sync can resume safely.
  7. Use the same pagination loop for subscribers, tags, custom fields, forms, landing pages, and segments.
  • Use limit to set how many records Mailrith should return in one API response.
  • Use starting_after only after Mailrith returns a next_cursor from the previous page.
  • Do not invent cursor values, count pages, or assume that a record's database order will never change.
  • For scheduled syncs, store the last cursor after you successfully process its page so a failed job can resume cleanly.
  • For one-time exports or migrations, keep requesting pages until has_more is false.
Paginated List Request
curl "https://api.mailrith.com/v1/subscribers?limit=50&starting_after=subscriber_123" \
  -H "Authorization: Bearer mrk_example_secret_key"
Paginated Response
{
  "data": [],
  "pagination": {
    "has_more": true,
    "next_cursor": "subscriber_456"
  }
}

Apply the Same Pattern Across Resources

List-style resources use the same pagination pattern. After your integration handles one list endpoint correctly, it can usually reuse the same loop for other resources.

Keep the loop simple: send a request, process every item in data, save the next cursor, and stop only when Mailrith says there are no more records.

Do not load an entire workspace into memory when the workspace may contain a large subscriber list. Process each page as Mailrith returns it, write progress to durable storage, and then request the next cursor.

  • subscribers are usually the largest list, so process subscriber records page by page.
  • Tags, custom fields, forms, landing pages, and segments may be smaller, but the same cursor loop keeps the integration consistent.
  • If a job stops after processing a page, resume from the cursor after the last fully processed page.
  • If you need a fresh full sync, start again without starting_after instead of reusing an old cursor from a different run.
GET /v1/subscribers

List subscribers

Returns subscribers in the authenticated workspace, sorted from newest to oldest.

View Schema
POST /v1/subscribers

Create or upsert a subscriber

Creates a new subscriber when the email does not exist in the workspace. If the email already exists, the API updates the existing subscriber unless create_only is true.

View Schema
PATCH /v1/subscribers/{subscriber_id}

Update a subscriber

Updates profile fields, status, custom fields, tags, or sequence assignments for one subscriber. Fields omitted from the request stay unchanged. Blank optional custom field values also leave saved values unchanged, and filled-in invalid values are rejected.

View Schema
PUT /v1/subscribers/{subscriber_id}/sequences/{sequence_id}

Add a subscriber to a sequence

Adds the selected subscriber to the selected sequence. If the subscriber is already in the sequence, the API returns the subscriber unchanged.

View Schema
DELETE /v1/subscribers/{subscriber_id}/sequences/{sequence_id}

Remove a subscriber from a sequence

Removes the selected subscriber from the selected sequence. If the subscriber is not in the sequence, the API returns the subscriber unchanged.

View Schema
DELETE /v1/subscribers/{subscriber_id}/tags/{tag_id}

Remove a tag from a subscriber

Removes the selected tag from a subscriber. If the subscriber does not have the tag, the API returns the subscriber unchanged.

View Schema
GET /v1/tags

List tags

Returns tags in the authenticated workspace.

View Schema
POST /v1/tags

Create a tag

Creates a new tag in the authenticated workspace. The GDPR consent tag names can be created and applied like other tags when you need to apply consent collected outside Mailrith. Tag-level double opt-in fields are no longer accepted; configure double opt-in on forms and landing pages instead.

View Schema
GET /v1/custom-fields

List custom fields

Returns custom fields in the authenticated workspace.

View Schema
POST /v1/custom-fields

Create a custom field

Creates a workspace-scoped custom-field definition.

View Schema
GET /v1/custom-fields/{custom_field_id}

Get a custom field

Returns one custom field from the authenticated workspace.

View Schema
PUT /v1/custom-fields/{custom_field_id}

Update a custom field

Updates a custom-field definition for the authenticated workspace.

View Schema
DELETE /v1/custom-fields/{custom_field_id}

Delete a custom field

Deletes a custom-field definition from the authenticated workspace.

View Schema
GET /v1/forms

List forms

Returns forms from the authenticated workspace.

View Schema
POST /v1/forms

Create a form

Creates a form in the authenticated workspace.

View Schema
GET /v1/forms/{form_id}

Get a form

Returns a form from the authenticated workspace.

View Schema
PUT /v1/forms/{form_id}

Update a form

Updates an existing form without creating a new form.

View Schema
DELETE /v1/forms/{form_id}

Delete a form

Deletes a form from the authenticated workspace.

View Schema
GET /v1/forms/{form_id}/submissions

List form submissions

Returns recent real submissions for one form, including the subscriber who submitted the form. Requires both `forms:read` and `subscribers:read`.

View Schema
GET /v1/segments

List segments

Returns saved segments from the authenticated workspace.

View Schema
POST /v1/segments

Create a segment

Creates a saved segment in the authenticated workspace.

View Schema
GET /v1/segments/{segment_id}

Get a segment

Returns one saved segment from the authenticated workspace.

View Schema
PUT /v1/segments/{segment_id}

Update a segment

Updates a saved segment in the authenticated workspace.

View Schema
DELETE /v1/segments/{segment_id}

Delete a segment

Deletes a saved segment from the authenticated workspace.

View Schema
POST /v1/segments/preview

Preview a segment definition

Returns subscriber counts for an unsaved segment definition. Include `current_segment_id` when previewing edits to an existing segment so circular segment references are rejected before saving.

View Schema

Need Help Shipping an Integration?

Reach the Mailrith team if you need help planning a sync, validating a webhook flow, or troubleshooting a request.

Contact Mailrith

On this page

Jump to the section you need.