API reference

Errors

HTTP status codes and machine-readable error codes returned by the LearningStudioAI public API.

The LearningStudioAI API uses standard HTTP status codes and a single JSON response shape. Every error response carries a machine-readable code for programmatic handling.

Response shape

All error responses are JSON with the same two fields:

{
  "message": "Human-readable description",
  "code": "MACHINE_READABLE_CODE"
}

Switch on code for programmatic handling. Surface message to your end users when appropriate — it's safe to display.

Status codes

Status When code
400 Body or query validation failed (e.g. subject missing or too long). VALIDATION_ERROR
401 Missing Authorization header, malformed Bearer prefix, or unknown key. INVALID_API_KEY
403 API key valid, but the account isn't on a paid plan. PAID_PLAN_REQUIRED
403 Out of monthly course credits on the current plan. USAGE_LIMIT_EXCEEDED_PLAN
404 Job or course not found, or belongs to a different key. NOT_FOUND
429 Rate limit exceeded for this endpoint. RATE_LIMIT_EXCEEDED
500 Internal error. Report to support if it persists. INTERNAL_ERROR

Machine-readable codes

Returned with 403 when the requesting account isn't on a paid plan.

{ "code": "PAID_PLAN_REQUIRED", "message": "API access requires a paid plan" }

The plan check runs on every request — a key stops working the moment the account is downgraded, and starts working again the moment it's upgraded.

To resolve: upgrade your plan. The existing key becomes valid on the next request after the plan change is processed.

USAGE_LIMIT_EXCEEDED_PLAN

Returned with 403 on POST /api/v1/courses when the plan's monthly course-credit allowance is exhausted.

{
  "code": "USAGE_LIMIT_EXCEEDED_PLAN",
  "message": "Usage limit exceeded for your plan (Pro)"
}

The check runs before the job is queued, so an over-quota request returns 403 immediately without consuming credits or producing a job. The message includes the plan name to help surface the right upgrade prompt to your end users.

To resolve: wait for the next billing-period reset, upgrade to a higher tier, or contact support.

Rate limits

Limits are per-key, sliding-window over 60 seconds.

Endpoint Limit
POST /api/v1/courses 30 / min
POST /api/v1/courses/:id/export 30 / min
GET /api/v1/courses/jobs/:jobId 120 / min

When you exceed a limit, the request returns 429 with body:

{ "message": "Too many requests", "code": "RATE_LIMIT_EXCEEDED" }

Standard rate-limit headers are included on every response:

Header Meaning
RateLimit-Limit Total requests allowed in the current window.
RateLimit-Remaining Requests left in the current window.
RateLimit-Reset Seconds until the window resets.

Network errors

Errors not produced by the API itself — TLS failures, connection resets, DNS issues — surface in your HTTP client as transport errors, not as JSON bodies. Treat them as transient.

When retrying POST /api/v1/courses after a transport error, the original request may have succeeded — you'll see a course.created webhook for the duplicate as well. Deduplicate on your side using jobId.