API Documentation
The Control is Better REST API allows active members to query the risk database programmatically. Integrate risk checks directly into your TMS, ERP, or quoting workflow.
Authentication
All API requests must include your API key in the X-API-Key HTTP header. You can generate your key from the API section of your member dashboard.
# Pass key in header (recommended) curl -H "X-API-Key: YOUR_64_CHAR_KEY" \ https://controlisbetter.org/api/v1/search.php?q=AcmeCargo
Rate Limits
Each API key is limited to 100 queries per day. The limit resets at midnight (UTC+3). Every response includes rate limit headers:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Your daily query limit |
| X-RateLimit-Remaining | Queries remaining today |
| X-RateLimit-Reset | Unix timestamp when limit resets |
Error Codes
| HTTP Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request — invalid parameters |
| 401 | Missing or invalid API key |
| 403 | Key suspended, revoked, or agreement not signed |
| 429 | Daily rate limit exceeded |
| 500 | Server error |
All error responses follow this structure:
{
"success": false,
"error": "Human-readable error message",
"code": 401
}
Search Companies
Query the risk database for a company by name or tax/company ID. Returns all visible active reports for matching companies.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| q | string | required | Search term. Min 3 characters. |
| type | string | optional | name (default) or tax_id |
| country | string | optional | 2-letter country code (TR, DE, GB…). Filters results by country. |
Success Response
{
"success": true,
"query": "AcmeCargo",
"type": "name",
"country": null,
"result_count": 1,
"results": [
{
"company_name": "Acme Cargo Ltd.",
"tax_id": "1234567890",
"country": "TR",
"city": "Istanbul",
"threat_level": "high",
"report_count": 7,
"last_updated": "2026-03-15 14:22:00",
"reports": [
{
"report_id": 42,
"type": "concordat",
"filed_at": "2026-01-10 09:15:00",
"concordat_start": "2025-11-01",
"concordat_end": "2026-05-01",
"amount": 125000.00,
"currency": "USD",
"description": "Filed under court order."
}
]
}
],
"meta": {
"queries_used_today": 12,
"daily_limit": 100,
"remaining_today": 88,
"response_ms": 24
}
}
No results (company is safe)
{
"success": true,
"result_count": 0,
"results": []
}
Supported Countries
Returns all supported country codes and their ID type formats. No authentication required.
curl https://controlisbetter.org/api/v1/countries.php
Report Types
| type value | Meaning |
|---|---|
| enforcement_judgment | Enforcement proceedings based on a court judgment; the receivable is confirmed by a court but cannot be collected. Includes court_decision_date and case (enforcement office, file no, date). Published on approval. |
| enforcement_bill | Enforcement proceedings based on a cheque or promissory note that cannot be collected. Includes case. Published on approval. |
| bounced_cheque | Criminal complaint filed with the public prosecutor for a bounced cheque. case holds the prosecutor's office and investigation no. Published on approval. |
| enforcement_plain | Enforcement proceedings without a judgment (official enforcement file, no court ruling). Includes case. Published on approval. |
| unpaid_debt | Unpaid invoice / receivable with no proceedings. Visible only after 3+ independent claim-type reports or an official-file report on the same company. |
| concordat | Legacy member report: company under concordat. Includes start/end dates. Official concordat records are served separately. |
| court_decision | Legacy member report: unrecovered court judgment. Includes decision date. |
Every report item also carries official (boolean): true when the type is backed by an official file (published on approval), false for claim-type reports subject to the consensus threshold.
Threat Levels
| threat_level | Meaning |
|---|---|
normal | 1–5 active reports. Exercise caution. |
high | 6+ active reports. High risk — avoid or require upfront payment. |
Code Examples
Python
import requests API_KEY = "your_64_char_key" BASE_URL = "https://controlisbetter.org/api/v1" def check_company(name): resp = requests.get( f"{BASE_URL}/search.php", params={"q": name, "type": "name"}, headers={"X-API-Key": API_KEY} ) data = resp.json() if data["result_count"] == 0: print(f"✓ {name} — no risk records found") else: company = data["results"][0] print(f"⚠ {company['company_name']} — {company['threat_level']} threat") print(f" Reports: {company['report_count']}") check_company("Acme Cargo Ltd")
PHP
$apiKey = 'your_64_char_key'; $query = 'Acme Cargo'; $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'https://controlisbetter.org/api/v1/search.php?q=' . urlencode($query), CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['X-API-Key: ' . $apiKey], ]); $response = json_decode(curl_exec($ch), true); curl_close($ch); if ($response['result_count'] > 0) { $company = $response['results'][0]; echo "RISK: {$company['company_name']} — {$company['threat_level']}\n"; } else { echo "SAFE: No records found.\n"; }
JavaScript (Node.js)
const response = await fetch( `https://controlisbetter.org/api/v1/search.php?q=${encodeURIComponent(company)}`, { headers: { 'X-API-Key': process.env.CIB_API_KEY } } ); const data = await response.json(); if (data.result_count === 0) { console.log('✓ No risk records found'); } else { console.log(`⚠ Threat level: ${data.results[0].threat_level}`); }
Contact us at info@controlisbetter.org to discuss enterprise API access.