REST API
Errors
HTTP status codes, machine-readable error codes, and the extra fields that accompany errors.
When a request fails, the response body has this shape:
{
"ok": false,
"error": "similar",
"message": "Benzer adlı firma var — mevcut kaydı seçin ya da confirm_new=1 ile yeni açın.",
"similar": [ { "id": 7, "name": "Alize Paketleme San. ve Tic. A.Ş.", "…": "…" } ]
}erroris a stable, machine-readable code — branch on it in your code.messageis a Turkish description you can show to users; its wording may change, so don't parse it.- Some errors carry extra fields:
similar,customer,gate_problems,module,state,otp.
Error codes
| Code | HTTP | Meaning |
|---|---|---|
unauthorized |
401 | Missing, invalid, expired or revoked token. |
credentials |
401 | Wrong username or password. |
otp_required |
401 | Two-factor code required (otp). |
otp_invalid |
401 | Wrong or expired two-factor code. |
forbidden |
403 | You may not see / edit this record. |
insufficient_scope |
403 | The OAuth token lacks crm.write. |
module |
403 | The module is off in the licence or for the user. |
license |
403 | The licence expired — admins only. |
ip |
403 | Access from this network is not allowed (IP restriction). |
not_found |
404 | Record not found. |
invalid |
400 | Missing or invalid field (message explains). |
send |
400 | The e-mail could not be sent (no mailbox, bad recipient…). |
exists |
409 | A company with this name exists (returned in customer). |
similar |
409 | Similar names exist (similar); send confirm_new: true to create anyway. |
gate |
409 | Stage gate not met (gate_problems). |
locked |
429 | Too many failed sign-ins — wait 60 s. |
rate_limited |
429 | Per-minute request limit exceeded (Retry-After). |
limit |
429 | Hourly question limit per user (40) reached. |
HTTP status codes
| Code | Meaning |
|---|---|
200 |
Success. |
201 |
Created (OAuth client registration, SCIM user creation). |
204 |
Success with no content (SCIM user deactivation). |
400 |
Missing or invalid field. |
401 |
Authentication failed — refresh the token or sign in again. |
403 |
Not permitted — role, module, scope, license, or IP. |
404 |
The record doesn't exist or is outside what you're allowed to see. |
405 |
Method not supported (for example, GET on the MCP endpoint). |
409 |
Business rule conflict — duplicate company, stage gate. |
429 |
Rate limit — wait for the number of seconds in Retry-After. |
500 |
Server error. If it keeps happening, send the request and the time to info@solk.app. |
Example: duplicate company
r = s.post(f"{BASE}/api/v1/customers", json={"name": "Alize Ambalaj"})
j = r.json()
if r.status_code == 409 and j["error"] == "exists":
company = j["customer"] # already exists — use it
elif r.status_code == 409 and j["error"] == "similar":
candidates = j["similar"] # let the user pick, or:
j = s.post(f"{BASE}/api/v1/customers", json={"name": "Alize Ambalaj", "confirm_new": True}).json()Example: stage gate
r = s.post(f"{BASE}/api/v1/opportunities/{oid}/stage", json={"stage": "Viable"})
if r.status_code == 409 and r.json()["error"] == "gate":
for problem in r.json()["gate_problems"]:
print("Missing:", problem)