Connect with Corteksa (Partners)
Connect with Corteksa (Partners)
Audience: an external app's backend developer (e.g. wieeo) letting a Corteksa customer connect their workspace and sync data.
TL;DR — the simple way (recommended): the customer generates an API key in
Corteksa and pastes it into your app. Your backend validates it with one call
(GET /api/v1/me), stores it, and uses it against the REST API. No OAuth, no
redirect, no app registration. One key = one workspace. This is the ClickUp
"personal token" model, and it's the fastest path to a working integration.
Prefer a one-click "Connect" button and don't want customers copy-pasting keys? That's the OAuth flow — see Advanced: OAuth Connect button at the end. Start with the API key below unless you specifically need it.
1. The flow
1. Customer (in Corteksa) Settings → API Keys → New key → copy it
2. Customer (in wieeo) paste the key → click Connect
3. wieeo backend GET https://{HOST}/api/v1/me (with the key)
200 → store {host, key}; show "Connected to <Workspace>"
401 → "That key isn't valid"
4. wieeo syncs GET/POST https://{HOST}/api/v1/object/data/:slug (with the key)2. Which Corteksa host to use
The host decides which Corteksa database the request hits — before the key is even read. So it matters, and it differs by customer type:
| Customer type | Host | What to do |
|---|---|---|
| Standard (shared/free tier — the majority) | app.corteksa.net — fixed | Hardcode it. The key alone resolves the workspace; don't ask for a URL. |
| Enterprise (their own Corteksa domain) | e.g. acme.corteksa.net | Ask once (a "custom domain" field). The key only works on its own host. |
Store the host with the key after connecting, and reuse it for every call.
Throughout this doc, {HOST} = the host chosen here.
3. Connect — validate the pasted key with GET /api/v1/me
When the customer pastes a key and clicks Connect, call /me to (a) confirm the
key is valid and (b) get the workspace name to display. Send the key as a Bearer
token or the X-Api-Key header — both work:
GET https://{HOST}/api/v1/me
Authorization: Bearer crtk_live_…200 — valid key:
{
"message": "Success",
"data": {
"workspace_name": "Acme Sales",
"workspace_id": 42,
"tenant_type": "hyper",
"scopes": ["read.contacts", "create.contacts", "update.contacts"]
}
}→ Store { host, key }, and show "Connected to Acme Sales." You can also
pre-check scopes to warn if a permission you need is missing.
401 — invalid / revoked / expired key → reject with "That key isn't valid."
/me needs no scope — any valid key can call it. workspace_id is null for
enterprise/dedicated tenants (tenant_type: "dedicated"); the key still works.
4. Calling the API with the key
Send the key on every request against the customer's host:
GET https://{HOST}/api/v1/object/data/contacts
Authorization: Bearer crtk_live_…Writing records — important: the data body is keyed by each field's slug
(e.g. name-8fk2), not its display name — a display-name key can 400 on a required field.
POST https://{HOST}/api/v1/object/data/contacts
Authorization: Bearer crtk_live_…
Content-Type: application/json
{ "data": { "name-8fk2": "Sara", "phone-p0zx": "+20…" } }A key can only reach the objects/actions in its scopes; anything else returns 403.
See every key-reachable endpoint in the Integration API Reference.
5. Scopes
Scopes are route-name strings: {action}.{objectSlug} — e.g. read.contacts,
create.contacts, update.contacts, delete.contacts. The customer picks them
when they mint the key. You can see a key's granted scopes in the /me response,
so check upfront that the ones you need are present. Confirm the exact object slugs
per customer — Corteksa schemas are customizable.
6. Disconnecting
The customer revokes the key in Corteksa (Settings → API Keys → Revoke). Your very
next call returns 401. Treat a sudden 401 as "disconnected": delete the
stored key and prompt the customer to reconnect with a fresh one.
7. Security checklist
- The key is a secret — store it encrypted, server-side, per customer. Never in a browser, app bundle, or logs.
- Store the host alongside the key — enterprise customers aren't on
app.corteksa.net. - Handle
401as disconnected → clear the stored key and re-prompt. - Never log the key; log only the
token_prefixif you need a reference.
Advanced: OAuth "Connect" button
Only reach for this if you're publishing a listed integration and want a one-click "Connect with Corteksa" button instead of customers pasting keys. It's more moving parts (a global app registration, a redirect, a consent screen) for a smoother UX. The API key flow above needs none of it.
Setup (one-time, done on the Corteksa side)
A Corteksa super-admin registers your app once (global registry) and hands you:
| Env var | What it is |
|---|---|
CORTEKSA_CLIENT_ID | Your app's public id (crtk_app_…) — same for every customer |
CORTEKSA_CLIENT_SECRET | Your app secret — server-side only |
CORTEKSA_REDIRECT_URI | Your callback, e.g. https://api.wieeo.com/api/v1/integrations/corteksa/oauth/callback — exact match |
You are a confidential client (you have a backend), so you authenticate the
token exchange with client_secret. One registration serves every customer,
hyper and enterprise alike — only the host differs (same rule as §2).
The flow
-
Redirect the browser to the consent page (generate a random
statefirst):https://{HOST}/en/oauth/authorize ?client_id=<CORTEKSA_CLIENT_ID> &redirect_uri=<CORTEKSA_REDIRECT_URI> (URL-encoded, exact match) &scope=read.contacts%20create.contacts%20update.contacts &state=<random-opaque-string> &response_type=codeThis is the Corteksa web app (it renders approve/deny), not the API.
-
User approves → browser returns to your
redirect_uriwith?code=…&state=…. Verifystate. Thecodeis single-use and expires in 60 seconds. -
Exchange the code for tokens (server-to-server):
POST https://{HOST}/api/v1/oauth/token Content-Type: application/json { "grant_type": "authorization_code", "code": "<code>", "redirect_uri": "<CORTEKSA_REDIRECT_URI>", "client_id": "<CORTEKSA_CLIENT_ID>", "client_secret": "<CORTEKSA_CLIENT_SECRET>" }Response (raw RFC 6749 JSON):
{ access_token: "crtk_oauth_…", refresh_token, token_type, expires_in, scope }. -
Store
{ host, access_token, refresh_token, expires_at }per customer. The token carries the workspace — you don't trackworkspace_id. (You can callGET /api/v1/mewith thecrtk_oauth_token too, to show the workspace name.)
Refresh
Access tokens last ~1 hour. Refresh with grant_type: "refresh_token" (+ client_id
/ client_secret). Refresh tokens rotate — every refresh returns a new
refresh_token and invalidates the old one; always persist the new value.
Disconnect / revoke
- You revoke:
POST https://{HOST}/api/v1/oauth/revoke{ token, client_id, client_secret }(RFC 7009). - The customer revokes in Corteksa (Settings → Connected apps) → your tokens stop
immediately → treat a
401as disconnected.
Security
client_secret server-side only · state on every authorize · exact redirect_uri
· tokens are secrets, stored per customer · rotate the refresh_token on every refresh.