SELMA API User Guide

Getting Started

1. Obtaining API Access

To access the SELMA API, your SELMA administrator will create an API user account for you. They will provide you with:

  • Your API username in the format: selma_{environment}_{random_string} (e.g., selma_prod_abc123def4)

2. Generating Your Initial API Secret

After your administrator creates your account, you must generate your API secret:

  1. Navigate to /api/docs in your SELMA instance
  2. Login with your SELMA credentials
  3. Find your API username in the API Users section
  4. Check the safety checkbox to enable the Regenerate button
  5. Click Regenerate
  6. Confirm the action when prompted
  7. IMPORTANT: Copy the generated secret immediately – it will only be shown once!
  8. Click “I have saved the key” to close the dialog
  9. Store the secret securely in your application’s configuration

3. Regenerating Your API Secret

If you need to regenerate your secret (for security rotation or if compromised):

  1. Follow steps 1-9 above
  2. Warning: Regenerating immediately invalidates your previous secret
  3. Update all applications using the old secret before regenerating to avoid downtime

4. API Documentation Access

The Swagger UI at /api/docs provides:

  • Interactive API documentation
  • Request/response schema examples
  • API specification downloads (JSON, JSON-LD formats)

Authentication

Obtaining a JWT Token

To authenticate with the API, exchange your credentials for a JWT token:

Request:

POST /api/auth

Content-Type: application/json

{

“username”: “selma_prod_abc123def4”,

“secret”: “your-secret”

}

Response:

{

“token”: “eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9…”

}

Using the JWT Token

Include the token in the Authorization header for all subsequent requests:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9…

Token Expiration: JWT tokens expire after a set period. When expired, simply request a new token using the same authentication endpoint.

Making API Requests

Request Format

All API endpoints follow RESTful conventions:

  • GET – Retrieve resources
  • POST – Create new resources
  • PATCH – Update existing resources
  • PUT – Replace existing resources
  • DELETE – Remove resources

Response Format

By default, responses are in JSON-LD format. You can request different formats:

  • /api/students – JSON-LD (default)
  • /api/students.json – JSON
  • /api/students.jsonld – JSON-LD

Pagination

Collection endpoints are paginated by default (30 items per page):

GET /api/students?page=2

Pagination Response:

{

“@context”: “/api/contexts/Student”,

“@id”: “/api/students”,

“@type”: “hydra:Collection”,

“hydra:totalItems”: 150,

“hydra:member”: […],

“hydra:view”: {

“@id”: “/api/students?page=2”,

“@type”: “hydra:PartialCollectionView”,

“hydra:first”: “/api/students?page=1”,

“hydra:last”: “/api/students?page=5”,

“hydra:previous”: “/api/students?page=1”,

“hydra:next”: “/api/students?page=3”

}

}

Filtering

Most collections support filtering:

# Search by partial name

GET /api/students?name=john

# Search by exact code

GET /api/students?code=STU001

# Filter by date range

GET /api/intakes?start_date[after]=2025-01-01&start_date[before]=2025-12-31

# Multiple filters

GET /api/organisations?name=university&city=auckland

Common Operations

Creating a Student

POST /api/students

Content-Type: application/json

Authorization: Bearer {token}

{

“code”: “STU12345”,

“first_name”: “John”,

“last_name”: “Smith”,

“email”: “john.smith@example.com”,

“date_of_birth”: “1995-06-15”,

“gender”: “/api/genders/1”,

“student_status”: “/api/student_statuses/1”

}

Creating an Enrolment

POST /api/enrolments

Content-Type: application/json

Authorization: Bearer {token}

{

“student”: “/api/students/123”,

“intake”: “/api/intakes/45”,

“start_date”: “2025-02-01T00:00:00+13:00”,

“end_date”: “2025-11-30T23:59:59+13:00”,

“enrolment_status”: “/api/enrolment_statuses/1”

}

Retrieving Resources by Alternative ID

Some resources support alternative identifiers:

# Get student by other_id_1

GET /api/students/other_id_1/{other_id_1}

# Get organisation by tax number

GET /api/organisations?tax_number=123456789

Error Handling

Error Response Format

Errors follow RFC 7807 Problem Details standard:

{

“@context”: “/api/contexts/Error”,

“@type”: “hydra:Error”,

“hydra:title”: “An error occurred”,

“hydra:description”: “student is already enrolled in this intake”,

“trace”: […]

}

Common Error Codes

  • 400 Bad Request – Invalid input data
  • 401 Unauthorized – Missing or invalid authentication
  • 403 Forbidden – Insufficient permissions or accessing another account’s data
  • 404 Not Found – Resource doesn’t exist
  • 422 Unprocessable Entity – Validation errors
  • 429 Too Many Requests – Rate limit exceeded

Rate Limiting

The API implements two-tier rate limiting:

  • Per Minute: 100 requests per minute (sliding window)
  • Per Day: 20,000 requests per day (fixed window)

When you exceed a rate limit, you’ll receive a 429 Too Many Requests response. The response headers will indicate when you can retry:

X-RateLimit-Limit: 100

X-RateLimit-Remaining: 0

X-RateLimit-Reset: 1640995200

Best Practices

1. Secure Your Credentials

  • Never commit API secrets to version control
  • Use environment variables or secure key management systems
  • Rotate secrets regularly (recommended: every 90 days)

2. Handle Errors Gracefully

  • Implement retry logic with exponential backoff for 5xx errors
  • Log error responses for debugging
  • Don’t retry 4xx errors without fixing the request

3. Optimize API Usage

  • Use filtering to reduce payload sizes
  • Cache responses where appropriate
  • Batch operations when possible
  • Request only the fields you need

4. Monitor Your Usage

  • Track your API usage against rate limits
  • Set up alerts for approaching limits
  • Monitor the “Last API Access” information in the UI

5. Date/Time Handling

  • Always include timezone information in date inputs
  • Expect UTC times in responses
  • Use ISO 8601 format (e.g., 2025-06-06T12:00:00+13:00)

6. IRI References

When referencing related resources, use their IRI (Internationalized Resource Identifier):

  • Correct: “student”: “/api/students/123”
  • Incorrect: “student”: 123 or “student_id”: 123