- Overview
- How Custom Business Rules Work
- The Three Rule Services
- Example: Learner Double-Booked (Event Issues)
- Example: Instructor Rest Period (Personnel Issues)
- Example: Equipment Inspection Due (Resource Issues)
- Creating a Rule
- Building Your Endpoint
- What Administrate Sends
- What Your Endpoint Returns
- Issue Categories
- Testing and Monitoring a Rule
- Good to Know
- Troubleshooting
Overview
Administrate's built-in issue checks cover what most training organizations need to keep their schedule healthy. Out of the box, Administrate flags missing instructors, instructor and resource conflicts, workplace mismatches, missing achievements, calendar and holiday clashes, and events running below their target fill rate. Those checks feed the issue badges you already know from the dashboard, the event page and the personnel and resource screens.
Every organization also has rules that are entirely its own: a union agreement that guarantees instructors a rest period between shifts, a compliance team that inspects equipment on its own schedule, or a policy that a learner can never be in two classes at once. Custom Business Rules let you add those checks to Administrate's issue pipeline. Your rules run alongside the built-in checks, and anything they find appears in the same places, with the same badges, as Administrate's own issues.
How Custom Business Rules Work
A Custom Business Rule is a pointer to logic that lives outside Administrate. You decide what to check and how; Administrate decides when to ask and where to show the answer.
Whenever someone views something that carries issues, Administrate checks it against every active rule for that kind of thing. For each rule it:
- Gathers the data. If the rule has a context query, Administrate runs it to collect exactly the data your logic needs, for example each event's learners and their other bookings.
- Asks your endpoint. It sends that data to the rule's Webhook URL.
- Shows what comes back. Your endpoint replies with a list of issues for each event, contact or resource, and Administrate merges them with its own findings.
In the examples below, the logic is built in Administrate Automator, our drag-and-drop workflow builder. Each rule is a three-step workflow: a webhook receives the data, a step evaluates the rule, and a final step sends the result back. Any HTTPS endpoint that follows the contract in Building Your Endpoint works just as well.
The Three Rule Services
Each rule belongs to one rule service, which decides what the rule checks and where its results appear.
| Rule service | Checks | Your results appear in |
|---|---|---|
| Event issues | Events | The dashboard Upcoming Events widget and the event page Issues bar |
| Personnel issues | Contacts being staffed on an event | The Add Personnel window, the event's Personnel table and the Personnel Issues window |
| Resource issues | Resources booked on an event | The event Outline, the resource booking window and the Resource Issues window |
Personnel and resource rules also receive the event being staffed or resourced, so your logic can compare the person or resource against that specific event.
On the event page, the Issues bar brings all of it together: built-in and custom issues side by side, with the custom event issues shown under the purple cog.
Example: Learner Double-Booked (Event Issues)
The rule: a learner must never be booked on two events that overlap.
Rule configuration:
- Name: Check - Learner Conflict
- Rule service: Event issues
- Context query: each event in view with its sessions, plus every named, active learner and the sessions of their other bookings.
query($ids: [String!]!) { events(filters: [{field: id, operation: in, values: $ids}]) { edges { node { id title timeZoneName timeZonedStart timeZonedEnd sessions { edges { node { timeZonedStart timeZonedEnd lifecycleState } } } learners(filters: [{field: isUnnamed, operation: eq, value: "false"}, {field: lifecycleState, operation: eq, value: "active"}]) { edges { node { contact { id personalName { firstName lastName } learners(filters: [{field: lifecycleState, operation: eq, value: "active"}]) { edges { node { event { id title lifecycleState timeZonedStart timeZonedEnd sessions { edges { node { timeZonedStart timeZonedEnd lifecycleState } } } } } } } } } } } } } } }
The logic: the Automator workflow compares each learner's other sessions with the event's sessions and ignores cancelled ones. For every overlap it returns a generic issue with a readable reason.
The result: Priya Shah is booked on both Advanced Excel (09:00–17:00) and Leadership Essentials (13:00–16:00) on the same day. Both events show a purple cog in the Other column of the Upcoming Events widget. Expand an event to see the reason next to Administrate's own findings, such as a low fill rate.
On the event page, the same issue appears as a purple cog badge in the Issues bar. Hover over it to read the reason.
Example: Instructor Rest Period (Personnel Issues)
The rule: an instructor needs at least 8 hours' rest between teaching commitments.
Rule configuration:
- Name: Check - Instructor 8 hour break
- Rule service: Personnel issues
-
Context query: the event being staffed (using
$eventId) with its sessions, the candidate contacts, and those contacts' existing session and event bookings.
query($ids: [String!]!, $eventId: String!) { events(filters: [{field: id, operation: eq, value: $eventId}]) { edges { node { id title timeZoneName timeZonedStart timeZonedEnd sessions { edges { node { id timeZonedStart timeZonedEnd lifecycleState cancelledAt } } } } } } contacts(filters: [{field: id, operation: in, values: $ids}]) { edges { node { id personalName { firstName lastName } } } } contactBookings(first: 100, filters: [ {field: contactId, operation: in, values: $ids}, {field: bookingType, operation: in, values: ["session", "event"]} ]) { edges { node { start end title unconfirmed contact { id } entity { id ... on Session { parentEvent { id } } } } } } }
The logic: for each candidate, the workflow measures the gap between their other bookings and this event's sessions. Anyone with less than 8 hours' rest gets a generic issue, annotated Instructor rest period (8h).
The result: Jordan Blake teaches Advanced Excel until 17:00, and the Data Storytelling Masterclass starts at 19:00. When you add an instructor to the Masterclass, Jordan shows 1 Issue in the Availability column. Select Expand to see why. The annotation is the heading, and the reason sits underneath it.
Rules inform, they don't block: you can still add Jordan. Once Jordan is on the event, the issue follows them to the Personnel table and the event's Issues bar. Select the personnel badge to open the Personnel Issues window.
Example: Equipment Inspection Due (Resource Issues)
The rule: equipment must not be used on an event if its next safety inspection falls on or before the event.
Rule configuration:
- Name: Check - Inspection due
- Rule service: Resource issues
-
Context query: the candidate resources with their custom fields, plus the event (using
$eventId).
query($ids: [String!]!, $eventId: String!) { resources(filters: [{field: id, operation: in, values: $ids}]) { edges { node { id name type { name } customFieldValues { definition { label } value } } } } events(filters: [{field: id, operation: eq, value: $eventId}]) { edges { node { id title timeZoneName timeZonedStart timeZonedEnd } } } }
The Equipment resource type has a Next inspection due custom field. Resource custom fields are text fields, so the date is stored as YYYY-MM-DD.
The logic: if the inspection date is on or before the event's first day, the workflow returns a generic issue. If the equipment has no date at all, it returns a notice instead: a message for information that isn't counted as an issue.
The result: Projector Samsung_1 is due for inspection on 19 October, the day before Advanced Excel. Once it's booked on the session, the Outline shows an issue count next to it.
Select the count to open the booking and read the issue.
The resource badge in the event's Issues bar opens the Resource Issues window for the whole event.
Creating a Rule
- Go to Control Panel and, under System, select Custom Business Rules.
- Select Create new rule.
- Enter a Name that tells your team what the rule checks.
- Choose the Rule service: Event issues, Personnel issues or Resource issues.
- Enter the Webhook URL that receives the request. For Automator, this is the workflow's production webhook URL, and the workflow must be active.
- Optionally, enter a Context query (see below).
- Select Save.
Administrate checks the context query when you save, so a typo or an unknown field is caught straight away rather than at run time.
The rule's Details tab shows its configuration. Select Edit to change it.
Managing rules requires the Custom Business Rule view, edit and delete permissions.
Building Your Endpoint
What Administrate Sends
Administrate sends a POST request with a JSON body to your Webhook URL.
Without a context query, the body is the list of IDs to check. Personnel and resource rules also receive the event:
{
"ids": ["UGVyc29uOjY5", "UGVyc29uOjcw"],
"context": { "eventId": "Q291cnNlOjUwMA==" }
}
With a context query, the body is the query's data, exactly as the query returns it. Administrate always supplies $ids (the events, contacts or resources being checked). Personnel and resource rules can also declare $eventId. A context query lets you send everything your logic needs in one request, so your endpoint never has to call back into Administrate.
Tip: declare
$eventIdasString!(required) only if the rule makes no sense without an event. Administrate skips a rule whose required variables it can't supply. Declare it asString(optional) if the rule should still run, witheventIdarriving asnull.
What Your Endpoint Returns
Reply with HTTP 200 and a JSON object keyed by the IDs you were sent. Each value is a list of issues for that ID; an empty list means nothing to report.
{
"UGVyc29uOjY5": [
{
"category": "generic",
"data": {
"reason": "Jordan Blake needs 8h rest: 'Advanced Excel' ends Tue 20 Oct 17:00 BST, only 2h before this session starts"
},
"annotation": "Instructor rest period (8h)"
}
],
"UGVyc29uOjcw": []
}
| Field | Required | Meaning |
|---|---|---|
category |
Yes | The kind of issue. Use generic for your own checks; see Issue Categories. |
data |
Yes | The fields for that category. For generic it's { "reason": "..." }. |
annotation |
No | A short title. Administrate shows it as the issue's heading. |
Administrate validates responses strictly:
- Return only IDs you were sent; extra keys are ignored.
- Send exactly
category,dataand, optionally,annotationfor each issue. An issue with missing or extra fields is rejected. - IDs inside
data, such assession_id, must be Administrate GraphQL IDs.
Issue Categories
generic and notice work for every rule service, and they're what you'll use most:
category |
data |
Shown as |
|---|---|---|
generic |
reason (required), session_id (optional) |
An issue, with reason as its text |
notice |
message (required), session_id (optional) |
Information only. Notices are never counted in issue badges or totals. |
You can also raise some of Administrate's own issue types when your logic detects them:
| Rule service | Additional categories and their data
|
|---|---|
| Event issues |
missing_instructor (session_id), inactive_instructor (session_id, contact_id), inactive_resource (session_id, resource_id), mislocated_resource (session_id, resource_id), disqualified_staff (contact_id), fill_rate (current as a 0–1 ratio, target as a 0–100 percentage) |
| Resource issues |
out_of_service (session_id or null, resource_id), mislocated (session_id, resource_id) |
data keys use snake_case. Unknown keys are ignored, and an issue missing a required key is dropped.
Testing and Monitoring a Rule
Test tab. Run a rule without affecting anyone. Choose an event (for personnel and resource rules), add sample contacts, resources or events, then select Run both:
- Build payload shows exactly what your context query produces.
- Send to webhook shows your endpoint's response and how many results would apply.
Test runs never apply their results and aren't recorded in the logs.
Logs tab. Every live run is recorded with its outcome, HTTP status, duration, the number of results accepted and rejected, and the event it ran for. The rules list summarizes each rule's last run, recent runs and failures.
Good to Know
- Every active rule runs. If several rules share a rule service, each one is asked, and all their issues are shown.
- Rules never block. If an endpoint is slow, unreachable or returns something invalid, Administrate shows its own issues without that rule's results, and records the failure in the Logs tab.
- Keep endpoints fast. All rules for a check share a 10-second budget, and each request has 1 second to connect and 7 seconds to respond. A context query that fetches everything up front keeps your endpoint quick.
- Results are cached for 60 seconds. If your endpoint's data changes, Administrate shows the new result within a minute. Editing a rule takes effect immediately.
-
Use an unguessable URL. Requests carry a
User-AgentofAdministrate-CustomBusinessRules/1.0 (rule:<id>)but no signature, so treat the Webhook URL as a secret. - Removing a rule. Delete it from the rules list.
Troubleshooting
My rule shows nothing.
- Open the rule's Logs tab. A run is only logged when Administrate actually calls your endpoint; results served from the 60-second cache aren't logged again. If a rule never appears, check that its context query declares only variables Administrate can supply.
- If you're using Automator, check that the workflow is active. Its production webhook URL only responds while it is.
- Use the Test tab to see the payload your endpoint receives and the response it sends back.
- Make sure your response is keyed by the IDs you were sent and that each issue has a
categoryanddata.
The Logs tab shows rejected results. Your response didn't match the contract. Check for extra fields, missing data keys, or IDs your rule wasn't asked about.
The Logs tab shows timeouts. Your endpoint took longer than the time limit. Move data gathering into the context query, so your endpoint only has to evaluate it.
The issue text is cut off. Badges and tables show a single line. Keep reason short and specific, and put the rule's name in annotation.