The IntelliAuth SDKs wrap REST APIs. Everything an SDK does — sign-in, token refresh, MFA, fetching the user profile, managing applications — is HTTP calls underneath. If you'd rather skip the SDK, talk to those same REST APIs directly.
This page is for you if:
- You work in a language we don't ship an SDK for today (Go, Python, Ruby, Java, .NET, PHP, Rust, Elixir, you name it).
- You prefer fewer dependencies and would rather own the HTTP layer yourself.
- You're integrating from a context where running JS isn't practical — a shell script, a Postman test, a serverless function in another language.
- You're evaluating IntelliAuth and want to see the wire format before committing.
Download the contract
Section titled “Download the contract”The three formats:
- OpenAPI YAML — the canonical human-readable spec. Drop it into your code-gen tool of choice (openapi-generator, oapi-codegen for Go, etc.) to scaffold a typed client in any language.
- OpenAPI JSON — the same spec in JSON. Some tools (Swagger UI, certain IDE plugins) prefer this format.
- Postman 2.1 collection — every integrator-facing endpoint as a named Postman request, grouped by resource. Import into Postman, Insomnia, or Bruno and explore by clicking.
The bundle is scoped to the integrator surface — the subset of endpoints the SDKs wrap. See "What's in this surface" below for the exact list.
Authentication without an SDK
Section titled “Authentication without an SDK”The platform speaks plain OAuth 2.0 / OIDC. Two flows cover almost every direct-API case.
For backend services (machine-to-machine)
Section titled “For backend services (machine-to-machine)”The client credentials grant is the right flow. Get a token, cache it, refresh near expiry.
curl -X POST https://banking-cymmetri.intelliauth.local/oauth2/token \ -d "grant_type=client_credentials" \ -d "client_id=$INTELLIAUTH_CLIENT_ID" \ -d "client_secret=$INTELLIAUTH_CLIENT_SECRET" \ -d "audience=https://api.cymmetri.com" \ -d "scope=users:read audit:read"Response:
{ "access_token": "...", "token_type": "Bearer", "expires_in": 3600, "scope": "users:read audit:read"}Cache the token for expires_in seconds minus a 60-second safety margin; refresh before expiry. No refresh_token is returned — repeat the call to get a new one.
For browser flows (user sign-in)
Section titled “For browser flows (user sign-in)”Without the SDK you implement authorization-code-with-PKCE by hand. The wire format is in that topic. The hard bits the SDK handles for you that you must now handle yourself:
- Generating + storing the
code_verifierfor PKCE. - Generating + storing + validating the
stateparameter for CSRF defence. - The redirect / callback handling.
- Silent refresh on a background timer.
- Tab synchronisation if your app is multi-tab.
- The MFA flow ID stash if your sign-in policy includes MFA.
This is enough work that a thin custom SDK in your language usually pays back. The OpenAPI spec gives you typed types; the patterns above plus the OAuth topics give you the flow shapes. Most teams build a ~300-line client and ship it.
For native and mobile
Section titled “For native and mobile”Same authorization-code-with-PKCE flow as browser, with the platform handoff documented in the native PKCE topic.
Making your first call
Section titled “Making your first call”Once you have a token:
curl https://banking-cymmetri.intelliauth.local/api/v1/me/profile \ -H "Authorization: Bearer $ACCESS_TOKEN"The response envelope:
{ "data": { "id": "usr_01HZ...", "email": "anita@cymmetri.com", "name": "Anita Singh", "email_verified": true }, "meta": {}}Every JSON response uses the same { data, meta } shape. List endpoints have a meta.next_cursor for pagination.
Handling errors
Section titled “Handling errors”When the platform refuses or fails:
{ "error": "permission_denied", "message": "You don't have permission to do that.", "details": { "required_scope": "users:write" }, "request_id": "req_01HZ..."}The full enumeration of error codes is in the error code index — the same list the SDKs match on. Branch on error, never on message text. Log request_id so support tickets can correlate to the exact call.
A reasonable client in 50 lines
Section titled “A reasonable client in 50 lines”For non-SDK languages, this is the shape of a minimum-viable client:
import timeimport requests
class IntelliAuth: def __init__(self, tenant_url, client_id, client_secret, audience): self.tenant_url = tenant_url.rstrip('/') self.client_id = client_id self.client_secret = client_secret self.audience = audience self._token = None self._token_expires_at = 0
def _get_token(self): # Refresh 60s before expiry if self._token and time.time() < self._token_expires_at - 60: return self._token res = requests.post(f"{self.tenant_url}/oauth2/token", data={ "grant_type": "client_credentials", "client_id": self.client_id, "client_secret": self.client_secret, "audience": self.audience, "scope": "users:read users:write", }) res.raise_for_status() body = res.json() self._token = body["access_token"] self._token_expires_at = time.time() + body["expires_in"] return self._token
def request(self, method, path, **kwargs): headers = kwargs.pop("headers", {}) headers["Authorization"] = f"Bearer {self._get_token()}" res = requests.request(method, f"{self.tenant_url}{path}", headers=headers, **kwargs) if res.status_code >= 400: body = res.json() if res.headers.get("content-type", "").startswith("application/json") else {} raise IntelliAuthError(body.get("error", "unknown"), body.get("message", res.text), body.get("request_id")) return res.json()
def list_users(self, **params): return self.request("GET", "/api/v1/users", params=params)
def create_user(self, **fields): return self.request("POST", "/api/v1/users", json=fields)
class IntelliAuthError(Exception): def __init__(self, code, message, request_id=None): super().__init__(message) self.code = code self.message = message self.request_id = request_idThat's the pattern — token caching, header injection, error wrapping. Scale up by adding methods for the endpoints your code actually touches. If you use the OpenAPI spec for code generation, typed versions of these come for free.
The Go, Ruby, Java, and .NET equivalents all have the same shape. The OpenAPI + Postman downloads give you the contract; this skeleton gives you the structure; your code fills in the verbs you care about.
What's in this surface
Section titled “What's in this surface”The downloads above contain the integrator-facing endpoints — the subset the SDKs wrap. Concretely:
| Path prefix | Purpose |
|---|---|
/oauth2/* | Token issuance, revocation, introspection, OIDC discovery |
/.well-known/* | OIDC discovery + JWKS |
/api/v1/auth/* | Sign-in, sign-out, MFA flow, WebAuthn ceremony |
/api/v1/me/* | Self-service for the signed-in user |
/api/v1/users/* | Admin user CRUD + bulk import |
/api/v1/groups/* | RBAC: groups + membership |
/api/v1/applications/* | Application CRUD + secret rotation |
/api/v1/resources/* + /api/v1/resource-types/* | ReBAC: resources + relations + checks |
/api/v1/federation/* | Programmatic SSO connection management |
/api/v1/webhooks/* | Webhook subscription management |
The full request / response / error shapes for each are in the per-resource API reference topics. Or click through the Postman collection — every endpoint has the request shape, an example body, and the auth header pre-configured.
What's NOT in this surface
Section titled “What's NOT in this surface”These exist on the platform but are intentionally not part of the integrator REST API. They're operated by humans in the tenant admin console:
- Flows and Actions — custom auth-flow orchestration is web-configured in the tenant admin console.
- Reports — the tenant admin's analytics catalogue is web-only.
- Audit reading — the tenant admin reads audit logs in the console. For integrator-side event consumption, subscribe to webhooks instead.
- Threat intelligence feeds — feed configuration is web-only.
- Branding — logo, theme, email templates are web-only.
- Breach incident management — read + resolve in the console. Integrators receive the
security.breach_incident_openedwebhook and act on it. - The control plane entirely — orgs, tenants, plans, billing, CP-level members. Web-driven at
https://manage.<DOMAIN_BASE>. See Control plane — for context.
The split is deliberate. Things that should happen with deliberate human attention happen on the web; things that need automation happen in the API.
Stay current
Section titled “Stay current”The OpenAPI spec above is versioned with the platform. We bump it on every release. To pull the latest in CI:
curl -fsSL https://docs.intelliauth.local/openapi/intelliauth.openapi.yaml \ > vendor/intelliauth.openapi.yamlRe-run codegen on the updated YAML to pick up any new endpoints or fields automatically.