Examples & reference
Example: Daycare Operations app (External)
A self-contained worked example showing how to build an External app that targets daycare center tenants (
daycare_center) — the new tenant type added to the Okta platform for leaf operating entities.
Why External and not Embedded?
Daycare centers need operationally-specific features: attendance check-in/check-out, daily reports pushed to guardians, and authorized pickup management. These are short-lived (daily) records that typically live in the partner's own store and integrate with third-party messaging or biometric hardware. External is the right fit because:
| Reason | Detail |
|---|---|
| Operational data stays with the partner | Attendance logs, daily reports, and pickup lists live in the partner's store, not in okta-web. |
| Independent stack | The partner may use biometric readers, RFID scanners, or existing mobile apps — none of which can be shipped inside okta-web. |
| Real-time guardian notifications | The partner's own messaging channels (WhatsApp, Push, SMS) are already configured on their infrastructure. |
| Full stack freedom | Any language or framework, without Embedded isolation constraints. |
Attendance records, daily reports, and pickup data are not stored in okta-web and are not defined as partner scopes — they are operational data owned entirely by the partner app. Scopes are used only to read the okta-web data needed for correlation (student roster, guardian contacts).
Tenant type daycare_center
The platform has added the daycare_center tenant type to the shared
canonicalTenantTypes catalog, which is pushed from okta-web to
okta-partners over the bridge. This means:
- The type appears automatically in the partner portal — no action needed on your side.
- You can declare
daycare_centeras a primary target tenant type when creating your app. daycare_centertenants can install your app and approve the requested scopes, just like any other tenant type.
No additional code is required to handle this type — once your app is published, the platform surfaces it to eligible tenants.
Required scopes
A daycare operations app needs to read student data from okta-web
to correlate it with its own operational records. Pick scopes from the
scope picker in the partner portal — the catalog is a mirror of
okta-web, kept in sync automatically in the partner_available_scopes
table. Do not hard-code scope names in your code; what appears in the
picker is the authoritative source.
| Scope | Why |
|---|---|
education.students.read |
Read the enrolled children for each tenant and match them with local attendance records. |
education.students.write |
Optional — only if the app needs to write back a custom field (e.g. an RFID card number). Request it only when needed. |
Least-privilege principle: start with
education.students.readonly. If you later need to write, addeducation.students.writein a new version with a clear reason in the manifest.
There is no attendance or daily-report scope because that data lives in your app's own store, not in okta-web.
Manifest
{
"moduleId": "daycare-ops",
"displayName": "Daycare Operations",
"version": "1.0.0",
"category": "operations",
"integrationType": "external",
"description": "Attendance check-in/out, daily guardian reports, and authorized pickup management for daycare centers.",
"scopes": [
{
"key": "education.students.read",
"required": true,
"reason": "Match tenant children with attendance and pickup records"
}
],
"external": {
"webhookUrl": "https://daycare.example/okta/webhook",
"webhookEvents": [
"education.students.created",
"education.students.updated",
"partner.installation.token_rotated"
],
"redirectUrls": ["https://daycare.example/oauth/callback"]
}
}
redirectUrls is useful if you want an OAuth-style flow after
installation — redirect the tenant to /oauth/callback, receive the
installation token, and run an initial roster sync.
Staying in sync via webhooks
After installation you receive subscribed events automatically. Verify the signature on every webhook (see Webhooks):
// Example: handling a student-update event
$event = $request->json('event'); // "education.students.updated"
$data = $request->json('data.student');
match ($event) {
'education.students.created' => $this->syncNewStudent($data),
'education.students.updated' => $this->updateStudentRecord($data),
'partner.installation.token_rotated' => $this->storeNewToken(
$request->json('data.new_token')
),
default => null,
};
return response()->json(['ok' => true]);
Respond 2xx within 10 seconds. For longer processing, return 202 immediately and handle via a background queue.
Recommended events for a daycare operations app:
| Event | When it fires |
|---|---|
education.students.created |
A new child is added to the tenant |
education.students.updated |
A student's data changes (name, contact, ...) |
partner.installation.token_rotated |
The tenant rotated the token — store the new one immediately |
Event names follow the canonical <feature>.<resource>.<action> format;
do not invent custom names.
Initial sync after installation
On first install, page through the full student roster to seed your local store:
# First page
GET /api/apps/education/students?page=1&per_page=100
Authorization: Bearer <installation_token>
# Repeat until last_page is reached
After the initial sync, rely on webhooks for incremental changes. This minimises API calls and keeps your data real-time.
Guardian notifications
Daycare-specific notifications (arrival, departure, daily report) go out through the partner's own channels (WhatsApp / SMS / Push) — they are not part of the Okta notifications system.
If you later want to unify notifications with the Okta platform so tenants can pick channels from their dashboard, you can declare a notifications catalog for your app — see the Notifications catalog section.
Step-by-step summary
- Create an External app in the portal; declare
daycare_centeras a target tenant type. - Request
education.students.readfrom the scope picker (addwriteonly if needed). - Subscribe to
education.students.created,education.students.updated, andpartner.installation.token_rotated. - Add a
redirect_urlif you want an OAuth-style initial-sync flow. - On install: fetch the full roster via pagination, then rely on webhooks for ongoing changes.
- Submit for review — the Okta team checks the manifest and webhook URL, then publishes the app to the marketplace.