App Events API
Let connected applications push calendar events to Campus One users who have granted consent.
App Events API
Connected applications can push calendar and scheduling events directly into a consented user's Campus One dashboard. Events appear in the Upcoming card (showing the next event) and in the This Week section (showing all events in the current calendar week).
Architectural Flow
Authentication & Authorization
All event requests require standard OIDC User Access Tokens.
- Required Scope:
events - Method: Bearer Token Authentication
- Header format:
Authorization: Bearer <access_token> - Admin prerequisite: The
permEventsflag must be enabled for your app in the Campus One admin console under SSO Config → Permissions.
The recipient user and origin app are resolved from the access token — apps do not supply a userId in the request body, preventing spoofing.
[!WARNING] If the token is expired, lacks the
eventsscope, or the app'spermEventsflag is disabled, the gateway returns401 Unauthorizedor403 Forbidden.
REST API Reference
Create Event
Push a calendar event to the authenticated user.
POST /api/apps/events
Headers
| Header | Type | Description |
|---|---|---|
Authorization | string | Required. Bearer <access_token> with the events scope. |
Content-Type | string | Required. Must be application/json. |
Idempotency-Key | string | Optional. Supply a unique key to prevent duplicate events if the request is retried. Keys are scoped per app and expire after 24 hours. |
Request Payload
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Event title (maximum 200 characters). |
description | string | No | Additional details about the event (maximum 1 000 characters). |
startsAt | string | Yes | ISO 8601 datetime when the event begins (e.g. 2026-06-15T14:00:00Z). |
endsAt | string | No | ISO 8601 datetime when the event ends. |
location | string | No | Venue or meeting link (maximum 300 characters). |
url | string | No | Deep-link back into your app for full event details. |
Example Integration
curl -X POST https://auth.campusone.com.ng/api/apps/events \
-H "Authorization: Bearer c1_act_abc123xyz" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: club-niletech-hackathon-2026" \
-d '{
"title": "NileTech Hackathon Finals",
"description": "Final round of the 2026 NileTech Hackathon. Teams present to judges.",
"startsAt": "2026-06-15T09:00:00+01:00",
"endsAt": "2026-06-15T17:00:00+01:00",
"location": "Engineering Lecture Theatre, Block C",
"url": "https://nilehub.nileuniversity.edu.ng/events/hackathon-2026"
}'const createEvent = async () => {
const response = await fetch('https://auth.campusone.com.ng/api/apps/events', {
method: 'POST',
headers: {
'Authorization': 'Bearer c1_act_abc123xyz',
'Content-Type': 'application/json',
'Idempotency-Key': 'club-niletech-hackathon-2026'
},
body: JSON.stringify({
title: 'NileTech Hackathon Finals',
description: 'Final round of the 2026 NileTech Hackathon.',
startsAt: '2026-06-15T09:00:00+01:00',
endsAt: '2026-06-15T17:00:00+01:00',
location: 'Engineering Lecture Theatre, Block C',
url: 'https://nilehub.nileuniversity.edu.ng/events/hackathon-2026'
})
});
if (!response.ok) {
const err = await response.json();
throw new Error(`Failed to create event: ${err.message}`);
}
const result = await response.json();
console.log('Event created:', result.id);
};import requests
headers = {
"Authorization": "Bearer c1_act_abc123xyz",
"Content-Type": "application/json",
"Idempotency-Key": "club-niletech-hackathon-2026"
}
payload = {
"title": "NileTech Hackathon Finals",
"description": "Final round of the 2026 NileTech Hackathon.",
"startsAt": "2026-06-15T09:00:00+01:00",
"endsAt": "2026-06-15T17:00:00+01:00",
"location": "Engineering Lecture Theatre, Block C",
"url": "https://nilehub.nileuniversity.edu.ng/events/hackathon-2026"
}
res = requests.post(
"https://auth.campusone.com.ng/api/apps/events",
json=payload,
headers=headers
)
if res.status_code == 201:
print("Event created! ID:", res.json()["id"])
else:
print("Failed:", res.status_code, res.text)Response Schemas
[!NOTE] The live, always-accurate schemas are published at the interactive API reference. The example below is illustrative — IDs are opaque strings (cuids) with no fixed prefix.
200 OK
The response body is the full created AppEvent record.
{
"id": "clh83kf1a0001st09k4m2p9zx",
"userId": "clx8z2abc1230009ab12cd34",
"appId": "clw7a1def4560002gh56ij78",
"title": "NileTech Hackathon Finals",
"description": "Final round of the 2026 NileTech Hackathon.",
"startsAt": "2026-06-15T08:00:00.000Z",
"endsAt": "2026-06-15T16:00:00.000Z",
"location": "Engineering Lecture Theatre, Block C",
"url": "https://nilehub.nileuniversity.edu.ng/events/hackathon-2026",
"createdAt": "2026-05-28T10:00:00.000Z",
"updatedAt": "2026-05-28T10:00:00.000Z"
}Error responses
A 401 (authentication) is rejected at the gateway and returns { "error": "..." }. A 400 (validation) or 403 (authorization) comes from the endpoint and returns the richer { code, status, message } object. See Status Codes & Errors for the canonical reference.
| Status | Body | Cause |
|---|---|---|
400 | { code, status, message, data } | Required fields missing or invalid (e.g. startsAt is not a valid ISO 8601 datetime). |
401 | { error } | Bearer token missing, invalid, expired, or not bound to a user. |
403 | { code, status, message } | Token lacks the events scope, or the app's permEvents flag is disabled. |
How Events Surface in the Dashboard
| Section | Behaviour |
|---|---|
| Upcoming card | Shows the single next event with startsAt ≥ now, sorted ascending. |
| This Week section | Shows all events whose startsAt falls within the current Monday–Sunday window. If no events exist this week, the section is retitled Upcoming and shows the next 5 future events instead. |
Events from all apps the student has consented to are merged and sorted together by startsAt.
Scope & Permission Requirements
| Requirement | Where it is set |
|---|---|
events scope in the OIDC token | The student grants this during the OAuth consent flow. |
permEvents = true on the app's SSO Config | An admin enables this in the Campus One admin console under Apps → [Your App] → SSO Config → Permissions. |
Both must be satisfied for POST /api/apps/events to succeed.