Skip to content
Open the app

Authentication, rate limits, and errors

The integration surface is small and consistent. This page covers the conventions that apply across it: how machine-to-machine endpoints authenticate, the rate limits, and the error shapes to expect.

Authentication

The server-to-server endpoints you'll integrate with — chiefly SIS sync — authenticate with a bearer token: a shared secret issued per institution, sent in the Authorization header.

POST /api/sis/sync
Authorization: Bearer <your-institution-secret>
Content-Type: application/json
Secrets are compared in constant time

Tokens are verified with a timing-safe comparison, so a wrong secret leaks no information about how wrong it was. Treat the secret like any production credential: store it in your secrets manager, never in source control, and rotate it if it may have been exposed.

End-user surfaces (the student app and staff console) authenticate with an HttpOnly session cookie established at sign-in, not a bearer token — see the OIDC flow. You won't call those as an integrator; the machine endpoints are the integration surface.

Rate limits

Endpoints are rate-limited per client. The limits are sized for legitimate use, so a well-behaved integration won't hit them:

EndpointLimit
SIS sync (/api/sis/sync)20 requests / minute

Exceed a limit and you get 429 Too Many Requests with a Retry-After header (seconds). Back off for that long and retry — don't hammer.

Sizes and idempotency

  • SIS sync accepts up to 5,000 students per request; a larger batch returns 413. Page your roster into batches under that cap.
  • SIS sync is idempotent. Re-sending the same students reconciles in place rather than duplicating, so retries after a network blip are safe.

Error shape

Errors return a JSON body with a stable, snake-case error code and sometimes a human-readable detail:

{ "error": "batch_too_large", "max": 5000 }

Common status codes across the surface:

CodeMeaning
200Success
400Malformed JSON or a missing required field
401Missing or incorrect bearer token
413Payload too large (e.g. over the batch cap)
429Rate limited — honour Retry-After
500Server-side failure
503Endpoint not configured (a required secret isn't set)
Branch on the code, not the message

The error codes are stable; the human-readable messages may be reworded. Write your integration to switch on the code (and the HTTP status), and log the message for humans.

Common questions

Is there a sandbox environment?

Integration happens against your institution's tenant. There's no separate public sandbox; coordinate test runs (for example a small SIS batch to a test cohort) during onboarding.

Do you offer outbound webhooks?

No — there are no outbound webhooks. See webhooks for what to do instead.

How do I rotate the secret?

Coordinate a new secret during onboarding or support; update it in your secrets manager and switch over. Rotate promptly if exposure is suspected.

Was this helpful?
Need more help?

The fastest answer is usually one question away.

Edit this page on GitHub