Pagination
All list endpoints in the Arsel API use cursor-based pagination. Cursors stay stable as new items are created or removed, and avoid the slow page-counts that offset pagination needs at scale.
Response Shape
Every paginated response has the same envelope:
{
"object": "list",
"has_more": true,
"data": [
/* page items */
]
}
| Field | Type | Description |
|---|---|---|
object | string | Always "list". |
has_more | boolean | true when there are more items beyond the current page. |
data | array | The items on this page. |
There is no total, page, or totalPages — those numbers are expensive to compute at scale and rarely needed in practice. Use has_more to drive your "next page" logic.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Items per page (min: 1, max: 100). |
after | string | — | Return items after this id (exclusive). Use the id of the last item from the previous page to fetch the next one. |
before | string | — | Return items before this id (exclusive). Use the id of the first item from a page to walk backwards. |
You can't pass both after and before in the same request. Doing so returns 400 bad_request.
Order
Results are always returned newest first. There is no sort_by parameter.
Forward Pagination
Walk from newest to oldest by reading the last item's id and passing it as after:
# First page
curl "https://api.arsel.sa/v1/contacts?limit=50" \
-H "Authorization: Bearer be_your_api_key"
# Next page — use the id of the LAST item from the previous response
curl "https://api.arsel.sa/v1/contacts?limit=50&after=01957e3a-4b5c-7d8e-9f0a-1b2c3d4e5f6a" \
-H "Authorization: Bearer be_your_api_key"
async function* paginate(url, apiKey) {
let cursor = null;
while (true) {
const u = new URL(url);
u.searchParams.set("limit", "100");
if (cursor) u.searchParams.set("after", cursor);
const res = await fetch(u, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const page = await res.json();
for (const item of page.data) yield item;
if (!page.has_more) return;
cursor = page.data[page.data.length - 1].id;
}
}
for await (const contact of paginate(
"https://api.arsel.sa/v1/contacts",
"be_your_api_key",
)) {
console.log(contact.id, contact.email);
}
Backward Pagination
To walk from a known point toward newer items, pass the id of the first item from the page you have as before:
curl "https://api.arsel.sa/v1/contacts?limit=50&before=01957e3a-4b5c-7d8e-9f0a-1b2c3d4e5f6a" \
-H "Authorization: Bearer be_your_api_key"
Endpoints That Paginate
Every list endpoint in the API uses this shape:
GET /contactsGET /listsGET /tagsGET /templatesGET /templates/galleryGET /propertiesGET /emailGET /smsGET /email/campaignsGET /sms/campaigns
Single-resource endpoints (GET /contacts/:id, etc.) and operation endpoints (e.g., POST /lists/:id/contacts) are not paginated.
Errors
| Error | When |
|---|---|
validation_error | limit outside the 1–100 range, or invalid types. |
bad_request | Both after and before provided in the same request. |