1. Guides
  2. Integrations
  3. Best Practices

Best Practices

Integrations — Best Practices

The recommended way to build a safe, resilient integration.

✓ Treat credentials as secrets

An API key (crtk_live_…), OAuth access/refresh token, and client_secret are all passwords. Store them encrypted, server-side, per customer — never in a browser, an app bundle, or logs. If you need a reference in logs, log only the non-secret token_prefix (crtk_live_a1b2c3d4), never the full value.

✓ Request least-privilege scopes

Ask for only the {verb}.{objectSlug} scopes you actually use — read.contacts before create.contacts, and neither if you only read one object. The customer sees exactly what you request on the consent screen, and a key can only ever be granted scopes its creator holds. Verify what you got via GET /me and warn early if a scope you need is missing.

✓ Prefer OAuth for published, multi-customer apps

A pasted API key fits a self-serve, single-workspace connection. For a listed integration serving many customers, use the OAuth "Connect" flow: tokens are revocable (a customer disconnecting kills live tokens at once, not at expiry) and short-lived, which limits blast radius if one leaks.

✓ Rotate the refresh token every time

The refresh_token grant rotates — each refresh returns a new refresh_token and invalidates the old one. Always persist the new value. Re-presenting an already-rotated refresh token is treated as a leak and revokes the entire token family, so a stale copy will lock you out.

✓ Handle 401 as "disconnected"

A revoked key or grant, or a lapsed expiry, returns 401 on the next call. Clear the stored credential and prompt the customer to reconnect — don't retry a dead credential in a loop.

✓ Verify every webhook signature

Recompute X-Corteksa-Signature (t=<unix>,v1=<hex>, where v1 is the lowercase hex HMAC-SHA256(signing_secret, "<t>.<raw-body>")) over the raw request body, keyed with the whole secret including its whsec_ prefix. Compare in constant time, and reject a t more than ~5 minutes from your clock to stop replays; retries are signed again, so the window does not reject them. Never trust a payload you haven't verified. Details and a test vector: Webhook events.

✓ Make webhook handlers idempotent

A delivery that times out (5 seconds), fails to connect, or gets a 5xx, 408 or 429 is retried, up to 3 attempts in total. No header or body field stays the same across attempts — X-Corteksa-Delivery, t and timestamp change every time — so do not dedupe on them. Treat a delivery as a signal: fetch the record by record_slug and apply its current state, so running the same delivery twice does no harm. Respond 2xx quickly and do heavy work asynchronously.

✓ Respect the rate limit

Each API key has a per-minute request limit. The count resets at the start of each clock minute. Batch where you can, and on 429 wait for the next minute and back off rather than hammering.

✗ Don't put the token flow in the browser

Never call POST /oauth/token, hold a client_secret, or handle a crtk_oauth_/crtk_refresh_ token in client-side code. The browser's only job in "Connect" is the consent screen, which yields a short-lived code delivered to your backend. Public (SPA/mobile) clients must use PKCE instead of a secret.

✗ Don't over-grant wildcards

{verb}.* scopes are convenient for a sync-anything mapping UI, but they expand to every object the owner can reach. Prefer explicit {verb}.{object} scopes unless the app genuinely needs breadth.

✗ Don't re-serialize the webhook body before verifying

Signatures are computed over the exact bytes sent. Parse the JSON after you've verified the signature over the raw body — re-encoding changes the bytes and breaks the HMAC.

✗ Don't rely on scopes for row-level security

Scopes gate which endpoints a credential can reach, not which rows. Data is still filtered per record by the acting admin's A/G/M/D level — never assume a read.contacts scope means "all contacts".

Next

  • When something breaks → Troubleshooting
  • Working code → Examples
Troubleshooting< PreviousConnect with Corteksa — Partner Integration GuideNext >

Powered by heyo-docs

On this page

✓ Treat credentials as secrets✓ Request least-privilege scopes✓ Prefer OAuth for published, multi-customer apps✓ Rotate the refresh token every time✓ Handle 401 as "disconnected"✓ Verify every webhook signature✓ Make webhook handlers idempotent✓ Respect the rate limit✗ Don't put the token flow in the browser✗ Don't over-grant wildcards✗ Don't re-serialize the webhook body before verifying✗ Don't rely on scopes for row-level securityNext