Pagination
Some endpoints return long lists. They return the list one page at a time.
These endpoints are paginated:
| Endpoint | Order |
|---|---|
GET /templates |
Most recently updated first. |
GET /contacts |
By phone number. |
GET /tags |
Oldest first (by id). |
GET /campaigns |
Newest first (by id). |
GET /phone-numbers returns all your numbers in one response.
Parameters
Section titled “Parameters”Send these as query parameters:
| Parameter | Default | Rules |
|---|---|---|
page |
1 |
The page number, starting at 1. A value below 1, or a value that is not a number, is treated as 1. |
limit |
50 |
Items per page, at most 200. A larger value is treated as 200. A missing, zero or non-numeric value is treated as 50. A negative value is treated as 1. |
Send whole numbers in range. Other values are not rejected, but they are not always replaced by the nearest allowed value:
- On
GET /tags,GET /contactsandGET /campaigns, a fractional value is first cut to a whole number (2.7becomes2,0.5becomes0), and then the rules above apply. - On
GET /templates, fractional values are not cut. Alimitbetween 0 and 1 becomes1, and a fractionallimitorpageabove 1 can fail with500 templates_lookup_failed.
The response repeats the page and limit that were used, and the items are in data:
{ "success": true, "page": 2, "limit": 50, "data": [ { "name": "order_update", "language": "en", "category": "UTILITY", "status": "APPROVED", "waba_id": "200000000000002", "components": [] } ]}The response does not include a total count or a “next page” link.
Reading all pages
Section titled “Reading all pages”Request page 1, then 2, then 3, and so on. Stop when a page has fewer items than limit.
That is the last page. If the total is an exact multiple of limit, the page after the last full
page is empty; stop there too.
async function listAllTemplates() { const limit = 200; const all = []; for (let page = 1; ; page++) { const url = `https://api.sanadwa.com/v1/templates?page=${page}&limit=${limit}`; const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.SANADWA_API_KEY}` }, }); if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`); const { data } = await res.json(); all.push(...data); if (data.length < limit) return all; }}import osimport requests
def list_all_templates(): limit, page, items = 200, 1, [] while True: res = requests.get( "https://api.sanadwa.com/v1/templates", params={"page": page, "limit": limit}, headers={"Authorization": f"Bearer {os.environ['SANADWA_API_KEY']}"}, timeout=30, ) res.raise_for_status() data = res.json()["data"] items.extend(data) if len(data) < limit: return items page += 1<?phpfunction listAllTemplates(): array { $limit = 200; $all = []; for ($page = 1; ; $page++) { $ch = curl_init("https://api.sanadwa.com/v1/templates?page=$page&limit=$limit"); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("SANADWA_API_KEY")], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, ]); $data = json_decode(curl_exec($ch), true)["data"]; $all = array_merge($all, $data); if (count($data) < $limit) return $all; }}curl "https://api.sanadwa.com/v1/templates?page=1&limit=200" \ -H "Authorization: Bearer $SANADWA_API_KEY"Order and changes between pages
Section titled “Order and changes between pages”If items are added, changed or deleted while you are reading pages, items can move between pages:
you may see an item twice or miss one. For example, templates are sorted by last update, so a
template that is approved while you read moves to the first page. If you need a complete list, read
all pages quickly and remove duplicates: by id for contacts, tags and campaigns, and by name,
language and waba_id for templates.
Every page counts toward your rate limit. Use limit=200 to make fewer requests.