Skoolyst Ads
Skoolyst Ads is the centralized advertising engine for the Skoolyst ecosystem. Advertisers submit ads, an admin reviews them, and any connected Skoolyst application can request and display approved ads for its own placements through one shared API.
Available — v1
Overview
Every Skoolyst application could build its own ad-management system, but that would mean repeating the same advertiser dashboard, moderation workflow and ad-serving logic in every app. Skoolyst Ads exists so this only has to be built once: it is a separate application that any Skoolyst property can connect to, so all of them share one advertising infrastructure instead of maintaining separate ones.
Three kinds of participants use it:
- Advertisers — sign up, submit ads for a specific connected app, and track their own ad's clicks and impressions.
- Admins — review and approve or reject submitted ads, manage which apps are connected, manage those apps' placements, and can pause or resume any ad.
- Connected apps — any other Skoolyst property (for example
teachers.skoolyst.com) that calls the Ads API to fetch an ad for one of its own placements and display it to its own users.
How it works, end to end
- An admin registers a connected app in Admin → Connected Apps, which generates an API key for that app.
- The admin defines that app's placements — the named slots an ad can be shown in, for example
header,footerorsidebar. Every connected app defines its own set of placements independently. - An advertiser creates an ad: they pick the target app, choose which of that app's placements it should run on, and provide the ad's content and an optional schedule.
- The ad starts in Pending status. An admin reviews it and either approves it (making it Active) or rejects it.
- The connected app calls the Ads API, asking "what ad should I show for placement X?" Skoolyst Ads returns one eligible active ad for that app and placement, or nothing if none qualifies.
- The connected app displays the ad and is responsible for reporting clicks and impressions back so the advertiser and admin can see performance.
Connected apps, API keys and placements
An advertiser can only target apps that an admin has already connected. Each connected app has:
- A name, code and domain.
- Its own API key, used to authenticate that app's requests to the Ads API. Keys can be regenerated by an admin if one is ever compromised.
- A status —
activeorpaused. A paused app's ads stop being requestable even if they were already approved. - Its own list of placements — named ad slots such as
header,footerorsidebar, managed from Admin → Connected Apps. Placement codes only need to be unique within that one app, not across the whole ecosystem, so two different apps can both have a placement calledheaderwithout conflicting.
A placement can only be deleted once no ad is still linked to it — this is a deliberate safeguard, since placements and ads are connected at the database level and removing an in-use placement would otherwise take its ads down with it.
Creating an advertisement
An advertiser submits an ad with the following:
| Field | Description |
|---|---|
| Advertiser name | The name shown as the ad's sender/sponsor. |
| Title & description | The ad's headline and supporting text. |
| Image | The ad creative shown alongside the text. |
| Call-to-action text | The button/link label, for example "Book Now" or "Learn More". |
| Click URL | Where a click on the ad should lead. |
| Target app | Which connected app this ad should run on. |
| Placement(s) | One, several, or all of the target app's placements — see below. |
| Start / end date | Optional schedule window. Left blank, an approved ad runs with no date restriction. |
Once created, an ad's target app and placement selection are fixed — they cannot be changed afterward. Everything else (title, description, image, CTA, click URL, schedule) can still be edited, which resets the ad back to Pending for re-review.
Targeting more than one placement
An ad is not limited to a single placement. If a connected app defines several placements — for example header, footer and sidebar — an advertiser can select any one of them, several, or all of them for the same ad, and it will run on every placement selected. This is handled by linking the ad to each chosen placement individually, rather than the ad only ever being able to point at one slot.
Moderation and ad status
Every ad moves through a status lifecycle that both the advertiser and the admin can see:
| Status | Meaning |
|---|---|
pending | Submitted (or just edited) and waiting for admin review. Not yet servable. |
active | Approved and within its schedule window — eligible to be returned by the API. |
paused | Temporarily stopped by an admin or advertiser without losing the ad's history. |
rejected | Reviewed and declined by an admin, with a reason recorded. |
ended | Past its scheduled end date. |
deleted | Removed by the advertiser or an admin. Kept as a soft delete rather than erased outright, so moderation history is preserved. |
Every moderation action an admin takes — approving, rejecting, pausing, reactivating, regenerating an app's API key, or changing a connected app's or placement's setup — is written to an audit log, so there is a record of who did what and when.
Click and impression tracking
Skoolyst Ads records impressions (how often an ad was shown) and clicks (how often it was clicked) per day, per ad. Advertisers can see these numbers for their own ads, and the admin can see totals across every ad, to understand which ads are performing well.
The Ads API
Connected apps fetch ads through one public endpoint. Full request/response reference:
# Get an ad for a placement
## Description
Returns one eligible ad for the requesting app's given placement, or
null if nothing currently qualifies (no approved ad targets that
placement, the app is paused, or nothing is within its schedule
window).
## Request
- Method: GET
- URL: /api/v1/ads/serve
- Headers: Authorization: Bearer <connected-app-api-key>
- Query: placement=<placement-code>
## Response
Status: 200 OK
Content-Type: application/json
{
"success": true,
"data": {
"ad": {
"id": 1,
"title": "Speak Confidently in 8 Weeks",
"description": "Small group classes",
"image_path": "/uploads/ads/example.jpg",
"cta_text": "Book Now",
"click_url": "https://example.com/enroll"
}
}
}
If nothing is eligible, "ad" is null rather than the request failing.
## Errors
| Status | Description |
|--------|-------------------------------------------|
| 401 | Missing or invalid API key |
| 404 | Unknown app or placement code |
Each connected app authenticates with its own API key rather than a shared one, so one app's key can be revoked or regenerated without affecting any other app's integration.
Version 1
What is documented on this page is Skoolyst Ads' first tracked release. It includes:
- Advertiser and admin accounts with role-based access
- Full ad CRUD: create, edit, pause/resume, delete (soft delete)
- Admin moderation: approve, reject, pause, reactivate, with an audit log of every action
- Connected app management with per-app API keys
- Placement management, scoped per connected app
- Multi-placement ad targeting — one ad can run on several of an app's placements at once
- Click and impression tracking, per ad and per day
- The public
GET /ads/serveAPI used by connected apps
See Versions for how this fits alongside the rest of the Skoolyst ecosystem, and Release Notes for the dated v1 entry. From here on, changes to Skoolyst Ads are tracked as bug fixes, modifications and updates against this baseline rather than as a from-scratch build.