API overview¶
Everything in the SkillFoundry web application is backed by a REST API you can use directly. This page covers the conventions that apply to every endpoint; the API reference lists the endpoints themselves, and the integration guide walks through a complete assessment flow.
Base URL and versioning¶
https://api.skillfoundry.dev/api/v1
All endpoints in these docs are relative to that base. The API is versioned by path prefix; v1 is the current (and only) version.
Interactive documentation generated from the live API is available at:
- Swagger UI:
https://api.skillfoundry.dev/api/v1/docs - ReDoc:
https://api.skillfoundry.dev/api/v1/redoc
The interactive docs are always in sync with the deployed API — when in doubt, they are authoritative for request/response schemas.
Authentication¶
Session tokens (JWT)¶
SkillFoundry uses a hosted identity provider (Descope). Sign-in happens in the browser (email/password, social login, or your organization's SAML SSO); the resulting session JWT authenticates API calls:
Authorization: Bearer <session-jwt>
- Tokens are short-lived; refresh is handled by the client SDK (there is no server-side refresh endpoint).
- Your user record is provisioned automatically on your first authenticated request.
- Roles (
candidate,interviewer,orgadmin,admin) are carried in the token and enforced per endpoint — the reference notes the required role where it's stricter than "any authenticated user".
For headless/server-to-server integrations, authenticate a service account through the identity provider's API to obtain a session JWT programmatically.
IDE session tokens¶
A second credential type exists for in-IDE assessment sessions: tokens with the prefix sf_ide_, minted per attempt (POST /attempts/{attempt_id}/ide-session, default 48-hour expiry, max 5 active per attempt). They're accepted as Bearer tokens on the subset of endpoints an IDE session needs: attempt start/submit, telemetry, behavioral events, and AI chat.
Requests and responses¶
- Request and response bodies are JSON (
Content-Type: application/json). - Timestamps are ISO 8601 strings in UTC.
- IDs are opaque strings — don't parse them.
Errors¶
Errors use standard HTTP status codes with a JSON body:
{ "detail": "Human-readable message" }
Validation failures (422) return field-level details:
{
"detail": [
{ "loc": ["body", "email"], "msg": "value is not a valid email address", "type": "value_error.email" }
]
}
| Status | Meaning | Typical causes |
|---|---|---|
| 400 | Bad request | Malformed input (e.g., an invalid PR URL) |
| 401 | Unauthorized | Missing, expired, or invalid token — re-authenticate |
| 403 | Forbidden | Insufficient role, not a member of the org, or subscription plan limit reached (the message says which, with an upgrade prompt) |
| 404 | Not found | Wrong ID, or a resource you can't see |
| 409 | Conflict | Duplicate (e.g., invitation already used) |
| 410 | Gone | Expired invitation |
| 422 | Validation error | Schema violations, with field details |
| 429 | Rate limited | Slow down and retry with backoff |
| 500 | Server error | Retry; if persistent, contact support with the error_id from the response body |
Rate limits¶
Requests are rate-limited per client IP:
| Scope | Limit |
|---|---|
| General API | 60 requests / minute |
| Auth-related paths | 10 requests / minute |
| Uploads | 5 requests / minute |
| Burst (any) | 20 requests / 10 seconds |
Some features carry their own limits (for example, public challenge submissions at 30/minute per user, AI chat at ~10 messages/minute, and 5 active IDE session tokens per attempt). A 429 response means back off and retry; use exponential backoff in integrations.
API usage may also count against your organization's subscription plan limits — exceeding those returns 403 (not 429) with an upgrade message.
Pagination¶
List endpoints take page (1-based) and limit query parameters (default limit is typically 10–50, max 50–100 depending on the endpoint) and return a pagination envelope:
{
"items": ["..."],
"pagination": { "total": 100, "pages": 10, "current": 1, "limit": 20 }
}
A few endpoints use skip/limit or page_size instead — the interactive docs show the exact parameters per endpoint.
WebSockets¶
Two streaming endpoints exist:
WS /api/v1/notifications/ws/{user_id}— real-time in-app notifications.WS /api/v1/code-execution/ws/{execution_id}— live stdout/stderr for a code execution started viaPOST /code-execution/execute; send{"type": "stdin", ...}for input or{"type": "terminate"}to stop.
Webhooks¶
Inbound webhooks currently cover billing only (Stripe → SkillFoundry). Outbound webhooks to customer systems are not yet available; poll the relevant resources (e.g., attempt status, score reports) in the meantime.
Health¶
GET /health (no auth, outside the /api/v1 prefix) returns service status and version — use it for uptime checks.