Attendance API (Developers)

Link external attendance and members into Semis Growth LMS using our REST API.

The Semis Partner API connects external member and attendance systems to Growth LMS. Use it to submit attendance from instructor-led training, employee development events, or other organisational learning programmes. Stable external identifiers support consistent member matching and attendance reconciliation.

Who this is for

This reference is for integration developers. You need an authorised organisation integration key and a server-side application that can make HTTPS requests.

Base URL

All partner endpoints live under a single base path:

https://semis.reispar.com/api/v1/partner/

Responses are plain JSON. Every request must be made over HTTPS.

Authentication

Authenticate with a secret API key using a bearer token in the Authorization header. Keys start with the prefix sk_.

Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Keep your key secret

Treat your API key like a password. Store it in a secure secret manager, never commit it to source control, and never expose it in browser or mobile client code. If a key is leaked, ask an organisation owner to rotate it immediately.

Getting a key

An organisation Owner or Co-Owner creates keys from Organisation Settings → Integrations. When creating a key they choose which scopes (permissions) it has. You'll receive the secret once, at creation time — copy it somewhere safe.

Scopes

Each key is granted only the capabilities it needs. Requests to an endpoint fail with 403 if the key lacks the required scope.

ScopeAllows
members:readRead member profiles
members:writeCreate and update members
completions:readCheck attendance eligibility
attendance:writeRecord attendance

Quick start

  1. Get a key

    Ask an organisation owner to create a key with the scopes you need.

  2. Sync your members

    Synchronise member records so attendance can be matched to the correct employee or learner.

  3. Record attendance

    Push attendance events as they happen. The endpoint is safe to retry.

Record a single attendance event:

curl -X POST "https://semis.reispar.com/api/v1/partner/attendance/" \
  -H "Authorization: Bearer sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "external_event_id": "evt_1024",
    "external_member_id": "emp_5567",
    "status": "present",
    "occurred_at": "2025-03-14T09:05:00Z"
  }'

Endpoints

Record attendance

POST/api/v1/partner/attendance/scope: attendance:write

Records an attendance event for a member at an event. This endpoint is idempotent — sending the same external_event_id + external_member_id again updates the existing record instead of creating a duplicate, so it's safe to retry.

Request body

FieldTypeRequiredNotes
external_event_idstringYesThe event's ID in your system
external_member_idstringYesThe member's ID in your system
statusstringNopresent (default), absent, late, or excused
occurred_atstring (ISO 8601)NoWhen the attendance happened
raw_payloadobjectNoAny extra data you want stored for reference

Example response (201 Created, or 200 OK when updating)

{
  "attendance_id": "0a5f...c31",
  "external_event_id": "evt_1024",
  "external_member_id": "emp_5567",
  "status": "present",
  "member_found": true,
  "created": true
}

Recommended practice

member_found tells you whether the attendance was matched to a known Semis member. If it's false, sync the member first (see below) and send the event again to link them.

Sync a member

POST/api/v1/partner/members/scope: members:write

Creates or updates a single member. Match is by external_member_id, then email.

Request body

FieldTypeRequiredNotes
external_member_idstringYesThe member's ID in your system
emailstringNoUsed to match existing members
first_namestringNo
last_namestringNo
employee_idstringNo
departmentstringNo
job_titlestringNo

Add ?dry_run=true to preview what would change without writing anything.

Example response (201 Created for new, 200 OK for updates)

{
  "external_member_id": "emp_5567",
  "email": "ada@example.com",
  "first_name": "Ada",
  "last_name": "Obi",
  "employee_id": "E-5567",
  "job_title": "Engineer",
  "departments": ["Engineering"],
  "created": true
}

Held for review

To protect existing member records, some updates are held for an organisation admin to approve. When that happens you'll get a 409 with "status": "pending_review" and a review_id. This is expected — an admin approves or rejects it inside Semis.

Sync many members at once

POST/api/v1/partner/members/batch/scope: members:write

Create or update up to 200 members in one call. Each member is processed independently, so one failure never rolls back the others.

Request body

{
  "members": [
    { "external_member_id": "emp_1", "email": "one@example.com", "first_name": "One" },
    { "external_member_id": "emp_2", "email": "two@example.com", "first_name": "Two" }
  ]
}

Example response (200 OK)

{
  "total": 2,
  "created": 1,
  "updated": 1,
  "blocked": 0,
  "failed": 0,
  "results": [
    { "index": 0, "external_member_id": "emp_1", "status": "created" },
    { "index": 1, "external_member_id": "emp_2", "status": "updated" }
  ]
}

Read a member

GET/api/v1/partner/members/{external_member_id}/scope: members:read

Returns the current member record, or 404 if no matching active member exists.

Check eligibility

GET/api/v1/partner/eligibility/scope: completions:read

Check whether a member is eligible to attend an event (for example, has completed a prerequisite). Pass both IDs as query parameters:

/api/v1/partner/eligibility/?external_member_id=emp_5567&external_event_id=evt_1024

Example response

{
  "eligible": true
}

Rate limits

Responses include rate-limit headers so you can pace your requests:

HeaderMeaning
X-RateLimit-LimitRequests allowed in the current window
X-RateLimit-RemainingRequests remaining
X-RateLimit-ResetWhen the window resets

If you exceed a limit you'll get a 429 response with a retry_after value (in seconds).

Bulk loads

For large imports, use the batch endpoint (up to 200 members per call) instead of sending one request per member. It's faster and easier on rate limits.

Errors

Errors return a JSON body with a detail message and a standard HTTP status code.

StatusMeaning
400The request was invalid (missing or malformed fields)
401Missing, invalid, or revoked API key
403The key lacks the required scope
404The requested resource wasn't found
409Conflict — held for review, or a competing update
429Rate limit exceeded — retry after retry_after seconds
{
  "detail": "external_member_id is required."
}

Recommended flow

  1. Sync members first

    Synchronise employee and learner records with members/ or members/batch/ before submitting their attendance.

  2. Record attendance as it happens

    Call attendance/ whenever someone checks in. Retry safely on failure.

  3. Reconcile

    If member_found is false, sync that member and resend the attendance event to link it.


Need a key or higher limits? Contact your organisation owner or the Semis team.