Corteksa
GuidesIntegrations

Overview

Integrations — Overview

How any external app (wieeo, Zapier/Make, a customer's own script) integrates with Corteksa. There are exactly two directions, and everything below hangs off them:

  • PULL — the app calls Corteksa's REST API to read and write records.
  • PUSH — Corteksa sends the app HMAC-signed webhooks when records change.

Together they are a full two-way sync. An app authenticates once, then does both.

The whole picture

PULL — the app calls us

Every request carries a credential and flows through one gate, four layers:

  1. Credential — an API key (crtk_live_…) or an OAuth access token (crtk_oauth_…).
  2. ApiAuthGuard — the single gate for humans and apps. It classifies the token, authenticates it, and attaches an acting-as-admin AdminUser carrying the credential's scopes (super-admin bypass forced off).
  3. PermissionGuard + @RouteName — the scope check. A key only reaches a route whose scope it holds (read.{objectSlug}, create.{objectSlug}, …).
  4. RLS + workspace pinning — even past the gate, every query is scoped to the credential's workspace by Postgres row-level security (on the shared hyper DB).

What an app can pull/push through this gate — the complete external surface today:

CapabilityEndpointsScope
IdentityGET /meany valid credential
DiscoveryGET /object/active, GET /object/field/active/:slugvalid key (fields need read.{obj})
Records — readGET /object/data/:slug (+ search / lookup / facets / relations / logs)read.{obj}
Records — writePOST/PUT/DELETE /object/data/:slug (+ bulk)create/update/delete.{obj}
WebhooksPOST/GET/DELETE /webhooks/subscriptions, GET /webhooks/eventsvalid key (subscribe needs read.{obj})

Admin, billing, roles, workspace settings, and the key/app management endpoints are human-only — a credential can never reach them.

⚠️ Write bodies are keyed by field slug (e.g. name-8fk2), not the display name. A display-name key can 400 on a required field. Discovery returns the slug.

Full endpoint list: Integration API Reference.

PUSH — we call the app

Instead of polling, the app subscribes an HTTPS endpoint and Corteksa pushes a signed POST on every record change:

  • Reuses the internal webhook engine (Bull delivery, retry/backoff, RLS-safe) — a "public subscription" is just a webhook owned by an API key.
  • Each delivery is HMAC-SHA256 signed (X-Corteksa-Signature: t=…,v1=…) with a per-subscription secret shown once at subscribe time.
  • No loops: an event caused by a write the app's own key made is never delivered back to that app — so a two-way sync can't echo.

Full contract + signature-verification recipe: Webhooks.

How an app connects — two supported paths

Both paths end at the same endpoints and the same scope model; they differ only in how the credential is obtained.

Paste-key (simple)OAuth "Connect" (published app)
Credentialcrtk_live_ API keycrtk_app_ client + crtk_oauth_ token
Who creates itthe customer (Settings → API Keys)you register the app once (super-admin)
Connect UXpaste the key → validate via /me"Authorize" redirect → code → token
Best forself-serve, one workspacea published multi-customer integration
DetailsAPI KeysAPI Keys → Phase 2

Why it scales

  • One gate, any credential — adding a credential type is one change in the classifier; humans and apps share the same door.
  • Scope = route name — a new endpoint inherits authorization for free.
  • Global auth capabilityApiAuthGuard's dependencies are app-wide, so opening a new controller to apps is a one-line guard swap, no wiring.
  • Webhooks extend, not fork — the push channel rode onto the existing engine; HMAC + loop-prevention layered on top.
  • Guardrail tests encode the invariants — RLS pinning and "no write route may skip its scope check" fail CI automatically, so the surface stays safe as it grows.

Onboarding the next app costs nothing (paste-key) or one registration (OAuth). Exposing the next capability is incremental — a scope + a guard swap for pull, a catalog entry + a listener for push.

On this page