OraTek API
REST · JSON · Bearer-token auth · HTTPS-only. Stable interface for managing your CRM data programmatically.
Authentication
Every request to /api/v1/* must include a Bearer token in the Authorization header. Issue tokens from Settings → API keys in the CRM. Admin role required.
# Request
GET https://api.oratekdx.info/api/v1/contacts
Authorization: Bearer otk_a1b2c3d4e5f6g7h8i9j0k1l2m3
The full token is shown once at creation. After that you can see its prefix (first 12 chars) in the Settings list. Lost the token? Revoke and create a new one.
Errors
All errors return JSON with a stable shape:
{
"error": "not_found",
"message": "Contact does not exist or has been deleted."
}
| Status | Error code | Meaning |
|---|---|---|
| 400 | no_fields | PATCH with empty body |
| 401 | missing_api_key | No Authorization header |
| 401 | invalid_api_key | Token doesn't match any issued key |
| 401 | revoked_api_key | Token was revoked |
| 403 | insufficient_scope | Token missing required scope (e.g. write) |
| 404 | not_found | Record doesn't exist in your org |
| 422 | validation | Body failed schema validation; details array lists issues |
| 429 | rate_limited | Too many requests; retry after Retry-After seconds |
Rate limits
5,000 requests per hour per org on Pro. Higher on Enterprise. Limits reset on a sliding window. When you exceed, you get a 429 with a Retry-After header.
Contacts
List contacts
Query params: limit (1–200, default 50), offset, label, stage, q (search name + company).
GET /api/v1/contacts?label=hot&limit=10
// Response
{
"data": [
{
"id": "a1b2c3d4-...",
"full_name": "Pinnacle Tox Lab",
"company": "Pinnacle Tox Lab",
"deal_stage": "qualified",
"deal_value": 28000,
"label": "hot"
}
],
"meta": { "count": 10, "limit": 10, "offset": 0 }
}
Create a contact
Requires write scope. All fields optional except at least one of full_name or company.
POST /api/v1/contacts
Content-Type: application/json
{
"full_name": "Wasatch Drug Testing",
"company": "Wasatch Drug Testing",
"email": "sales@wasatchdrug.example",
"phone": "801-555-0102",
"location": "Murray, UT",
"deal_stage": "qualified",
"deal_value": 42000,
"label": "hot",
"tags": ["employer", "utah"]
}
Returns the created contact with all server-set fields populated.
Get a contact
Update a contact
Send only the fields you want to change. Requires write. Triggers contact.updated webhook; deal_stage changes also trigger deal.stage_changed.
Delete a contact
Hard delete. Cascades to activities and webhook deliveries. Triggers contact.deleted.
Deals
List deals
Convenience view — contacts with deal_stage IS NOT NULL. Same shape as contacts list but only deal-relevant fields. Sort: deal_value DESC.
Tasks
List tasks
Query params: status (open|done|completed|cancelled), limit, offset.
Create a task
{
"title": "Call Pinnacle Tox Lab about Q3 contract",
"priority": "high",
"due_at": "2026-05-20T14:00:00Z",
"category": "call",
"contact_id": "a1b2c3d4-..."
}
Triggers task.created.
Update a task
Setting status to done or completed triggers task.completed.
Webhooks
Subscribe to events and OraTek will POST signed payloads to your URL. Create subscriptions from Settings → Webhooks in the CRM (admin only).
Available events
contact.created— new contact added (via UI, API, CSV import, or map prospecting)contact.updated— any field changed on a contactcontact.deleted— contact removeddeal.stage_changed— deal moved to a different pipeline stagetask.created— new tasktask.completed— task marked done
Payload shape:
{
"event": "deal.stage_changed",
"ts": "2026-05-14T18:24:30.000Z",
"payload": {
"contact": { "id": "...", "full_name": "...", "deal_stage": "negotiation", ... },
"new_stage": "negotiation"
}
}
Verifying signatures
Every delivery includes X-OraTek-Signature: sha256=<hex> — an HMAC-SHA256 of the raw request body using the secret OraTek issued when you created the subscription. Verify on your side before trusting the payload:
// Node.js example
import crypto from 'crypto';
function verifyOraTekWebhook(rawBody, headerSig, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha1', secret).update(rawBody).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(headerSig), Buffer.from(expected)
);
}
Quickstart: cURL
# Set your token
export ORATEK_TOKEN="otk_a1b2c3d4..."
# List your hot leads
curl -H "Authorization: Bearer $ORATEK_TOKEN" \
"https://api.oratekdx.info/api/v1/contacts?label=hot"
# Create a contact
curl -X POST \
-H "Authorization: Bearer $ORATEK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"full_name":"New Lab","company":"New Lab Co","deal_stage":"lead"}' \
"https://api.oratekdx.info/api/v1/contacts"
API changelog
- 2026-05-14 — v1 launched. Contacts CRUD, deals list, tasks CRUD, 6 webhook events.