API reference
Push contacts in from your own systems, fire transactional mail, and pull campaign results.
Base URL https://sendora.caresoft.co.in/api/v1. JSON in, JSON out.
Authentication
A client admin creates keys under Settings → API. The key is shown once; only a hash is stored, so it cannot be recovered later.
curl https://sendora.caresoft.co.in/api/v1/ping \
-H "Authorization: Bearer snd_live_..."
Every response carries ok: true or ok: false with an error object. Rate limits are per key and reported in X-RateLimit-Limit and X-RateLimit-Remaining.
Endpoints
| Method | Path | Scope | What it does |
|---|---|---|---|
| GET | /ping | — | Confirms the key works and names the account. |
| GET | /datasets | contacts | Every contact database, with counts. |
| POST | /datasets | contacts | Create a database. Body: name, description, tag. |
| GET | /contacts?dataset_id=1&page=1 | contacts | Paged contacts with their status and custom fields. |
| POST | /contacts | contacts | Upsert up to 1000 contacts. Matched on email inside the database. |
| POST | /send | send | One transactional email, right now, through your SES account. |
| GET | /campaigns | reports | The last 100 campaigns with headline numbers. |
| GET | /campaigns/{id} | reports | Full report for one campaign. |
| GET | /campaigns/{id}/recipients?status=bounced | reports | Per-contact results, paged. |
| GET | /suppressions | contacts | Everything blocked for this account, and platform-wide blocks. |
| POST | /suppressions | contacts | Block one or many addresses. Body: addresses[], channel. |
| DELETE | /suppressions | contacts | Release an address. Body: address. |
Adding contacts
Anything you put in fields becomes a merge variable, exactly like a column in an uploaded spreadsheet. Contacts are matched on the email address within that database, so re-sending the same payload updates rather than duplicates.
curl https://sendora.caresoft.co.in/api/v1/contacts \
-H "Authorization: Bearer snd_live_..." \
-H "Content-Type: application/json" \
-d '{
"dataset_id": 1,
"check_mx": true,
"contacts": [
{"email": "[email protected]",
"first_name": "Rao", "company": "Sunrise Multispeciality",
"city": "Thane",
"fields": {"beds": "120", "speciality": "Cardiology"}}
]
}'
{"ok":true,"added":1,"updated":0,"rejected":0,"errors":[]}
Transactional send
For one-off mail your own application triggers — a booking confirmation, a report link. It goes through the same SES account, MIME builder and suppression checks as campaigns.
curl https://sendora.caresoft.co.in/api/v1/send \
-H "Authorization: Bearer snd_live_..." \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"template_id": 4,
"variables": {"first_name": "Rao", "appointment_date": "12 March"}
}'
Or pass subject and html directly instead of a template id. Merge variables work in both.
ok: true with skipped: true and a reason, not an error. Refusing to send is the correct outcome, and your integration should not retry it.Reading results
curl "https://sendora.caresoft.co.in/api/v1/campaigns/12/recipients?status=bounced&per_page=500" \
-H "Authorization: Bearer snd_live_..."
Useful statuses: sent, delivered, opened, clicked, bounced, complained, unsubscribed, failed, skipped_suppressed, skipped_invalid.
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_json | The body was not valid JSON. |
| 401 | missing_key / invalid_key | No bearer token, or the key was revoked. |
| 403 | scope_missing | The key does not carry the scope this endpoint needs. |
| 404 | dataset_not_found | The id does not belong to this account. Ids are never shared across accounts. |
| 409 | duplicate_name | A database with that name already exists. |
| 412 | no_sender | No verified sending identity is set up yet. |
| 422 | bad_recipient | Something in the body was missing or malformed. The message says which. |
| 429 | rate_limited | Over the per-minute limit on that key. Check the X-RateLimit headers. |
| 502 | provider_error | Amazon refused the message. The message text is passed through unchanged. |