API reference
Every request goes to https://api.singlemail.singleton.com.tr with an Authorization: Bearer sm_… header. Bodies and responses are JSON.
Sending an email
POST /emails
{
"from": "Destek <destek@firma.com>",
"to": ["ali@ornek.com"],
"subject": "Talebiniz alındı",
"html": "<p>…</p>",
"tags": [{ "name": "type", "value": "ticket" }]
}
→ 200 { "id": "abe55c23-533d-41ad-8971-2dad84ad985b" }| Field | Type | Description |
|---|
from | string | A single sender: "address@domain" or "Name <address@domain>". The name may not contain @ , ; : < > "; the domain must be verified. |
to | string | string[] | Recipient(s). |
subject | string | Subject. |
html / text | string | At least one is required. |
cc / bcc / reply_to | string | string[] | Optional. |
headers | object | Up to 20 custom headers: List-Unsubscribe(-Post), In-Reply-To, References, X-*. Address and routing headers such as From, Sender, Bcc are rejected. |
tags | {name, value}[] | Labels returned in webhooks, useful for filtering. |
attachments | {filename, content | path, content_type, content_id}[] | content is base64, or path a public URL (fetched by SingleMail, max 10 MB). content_id for inline images. |
scheduled_at | string | ISO date or "in 10 minutes". |
Emails
| Method | Path | Description |
|---|
| POST | /emails | Sends an email. Supports the Idempotency-Key header. |
| POST | /emails/batch | Sends up to 100 emails in one request. |
| GET | /emails | Lists sent emails (?limit, ?after). |
| GET | /emails/:id | Returns a single email and its status. |
| GET | /emails/:id/events | Event history of an email. |
| PATCH | /emails/:id | Reschedules a scheduled email. |
| POST | /emails/:id/cancel | Cancels a scheduled email. |
Domains
| Method | Path | Description |
|---|
| POST | /domains | Adds a domain and returns its DNS records. |
| GET | /domains | Lists domains. |
| GET | /domains/:id | A domain and its DNS records. |
| PATCH | /domains/:id | Turns open/click tracking on or off. |
| POST | /domains/:id/verify | Checks the DNS records. |
| DELETE | /domains/:id | Deletes the domain. |
API keys
| Method | Path | Description |
|---|
| POST | /api-keys | Creates a key (full_access or sending_access). |
| GET | /api-keys | Lists keys. |
| DELETE | /api-keys/:id | Revokes a key. |
Webhooks
| Method | Path | Description |
|---|
| POST | /webhooks | Adds a webhook and returns its signing secret (whsec_…). |
| GET | /webhooks | Lists webhooks. |
| GET | /webhooks/:id | A webhook and its signing secret. |
| PATCH | /webhooks/:id | Updates endpoint, events or status. |
| DELETE | /webhooks/:id | Deletes a webhook. |
Suppressions
| Method | Path | Description |
|---|
| POST | /suppressions | Adds an address to the suppression list. |
| GET | /suppressions | Lists suppressed addresses. |
| DELETE | /suppressions/:idOrEmail | Removes an address from the list. |
List endpoints return { object: "list", has_more, data }. Use ?limit= (max 100) and ?after= with the last ID of the previous page.
Errors
Failed requests return: { statusCode, name, message }
| Code | name | Meaning |
|---|
| 401 | missing_api_key | No Authorization header. |
| 401 | restricted_api_key | A sending-only key called a management endpoint. |
| 401 | restricted_api_key | A sending-only key tried to read or cancel emails. |
| 403 | invalid_api_key | Invalid API key. |
| 429 | rate_limit_exceeded | 30 invalid keys from one IP; wait 10 minutes. |
| 403 | project_suspended | The project or company was suspended by an administrator. |
| 403 | sending_paused | Sending was paused because of a high bounce or complaint rate; your administrator reviews and resumes it. |
| 403 | plan_limit_reached | Your plan's domain or project limit is reached. |
| 403 | validation_error | Domain is not registered or not verified. |
| 404 | not_found | Resource not found. |
| 409 | concurrent_idempotent_requests | The first request with this key is still running. |
| 422 | validation_error | Invalid body; the message names the field. |
| 422 | content_rejected | The content looks like spam; score and reasons in the response say why. |
| 422 | phishing_suspected | Contains a form, script, javascript: link or a link to an IP address. |
| 422 | attachment_rejected | Executable or macro-enabled attachment. |
| 422 | recipient_rejected | Disposable, misspelled or non-receiving recipient domain. |
| 422 | blocklisted | A keyword or domain on the platform blocklist. |
| 429 | rate_limit_exceeded | Per-second request limit exceeded. |
| 429 | monthly_quota_exceeded | Your plan's monthly sending limit is used up; it resets on the 1st (UTC). |
| 429 | warmup_limit_exceeded | New accounts can reach a limited number of recipients per hour at first. |
| 429 | daily_quota_exceeded | The plan's or project's daily limit is used up; it resets at midnight UTC. |
Protection errors
When spam and abuse protection rejects a send, the response also names the check and the reasons. A blocked send isn't stored and doesn't count against your quota. In a batch, if one email is rejected none are sent; the message starts with the index, e.g. [3].
422
{
"statusCode": 422,
"name": "content_rejected",
"message": "Email content looks like spam (score 9.5): …",
"check": "content",
"score": 9.5,
"reasons": [
"Spam phrases: kazandiniz, hemen tikla (+3)",
"Subject is in capital letters (+1.5)",
"Uses a link shortener (+2)"
],
"details": [
{ "code": "spam_phrases", "params": { "phrases": "kazandiniz, hemen tikla", "points": 3 } },
{ "code": "spam_subject_caps", "params": { "points": 1.5 } },
{ "code": "spam_shortener", "params": { "points": 2 } }
]
}reasons is English text and may change. To show the reason in your own UI or to branch on it, use details, which lists the same reasons in the same order as a stable code plus params. The possible codes:
| code | check | params | Example |
|---|
reputation_bounce_rate | reputation | rate, limit | Bounce rate 7.4% in the last 24 hours (limit 5.0%) |
reputation_complaint_rate | reputation | rate, limit | Spam complaint rate 0.42% in the last 24 hours (limit 0.30%) |
reputation_paused | reputation | — | Paused by the reputation guard |
reputation_review_required | reputation | — | An administrator must review and resume the project |
warmup_limit | warmup | hourly, days | New accounts can reach 300 recipients per hour during the first 7 days |
recipient_disposable | recipients | recipient, domain | kisi@mailinator.com: disposable email address |
recipient_typo | recipients | recipient, domain, suggestion | ahmet@gmial.com: looks like a typo, did you mean @gmail.com? |
recipient_reserved | recipients | recipient, domain | test@example.com: reserved test domain that can't receive mail |
recipient_no_mx | recipients | recipient, domain | info@firma-yok.com.tr: the domain firma-yok.com.tr has no mail server |
blocklist_keyword | blocklist | keyword | Contains a blocked keyword ("deneme bonusu") |
blocklist_link_domain | blocklist | domain | Links to a blocked domain (kumar-sitesi.example) |
blocklist_recipient_domain | blocklist | domain | Recipient domain is blocked (rakip.example) |
blocklist_sender_domain | blocklist | domain | Sender domain is blocked (kumar-sitesi.example) |
attachment_extension | attachments | filename, ext | Attachment "fatura.pdf.exe" has a blocked file type (.exe) |
attachment_content_type | attachments | filename, contentType | Attachment "kurulum" has a blocked content type (application/x-msdownload) |
phishing_form | phishing | — | Contains an HTML form (emails must not collect input) |
phishing_script | phishing | — | Contains script, iframe or embedded objects |
phishing_event_handler | phishing | — | Contains inline JavaScript event handlers |
phishing_js_link | phishing | — | Contains a javascript:/data: link |
phishing_userinfo | phishing | host | Link hides its real destination with user@host (evil.example.net) |
phishing_ip_link | phishing | host | Links to a bare IP address (185.12.4.9) |
spam_phrases | content | phrases, points | Spam phrases: kazandiniz, hemen tikla (+3) |
spam_subject_caps | content | points | Subject is in capital letters (+1.5) |
spam_subject_exclamation | content | points | Too many exclamation marks in the subject (+1) |
spam_money_symbols | content | points | Money symbols ($$$) (+1) |
spam_shortener | content | points | Uses a link shortener (+2) |
spam_punycode | content | points | Links to a punycode (look-alike) domain (+1.5) |
spam_link_mismatch | content | host, points | Link text shows one domain but points to another (secure-login.example.net) (+3) |
spam_many_links | content | points | Very many links (+1) |
spam_lure | content | points | Account or payment lure linking to another domain (+2.5) |
spam_image_only | content | points | Image-only email without text (+2) |
Using your own full-length links, not writing subjects in capitals and not showing another domain in link text avoids most content rejections. If you think a rejection is wrong, talk to your SingleMail administrator; they can adjust the check for your account.