Training sessions and recordings
Browse published live sessions and recordings
/a/Training_list
Browse published live sessions and recordings
When to use this endpoint
Discover session IDs from Upcoming Live Webinars, a bounded calendar window, or the on-demand recording catalogue, then load Training_get before presenting actions. This is a shared training catalogue enriched with the current user’s interest and booking state, not a tenant’s job/training-object list.
Authentication and permissions
Authenticate with signed API-key fields or a logged-in CRM session. Every Training handler requires login; there is no additional page, role, department, or tenant feature-flag check. CRM2 exposes Training to authenticated users.
Webinars and session IDs belong to a shared global catalogue. Interests and provider registrations are scoped to the authenticated tenant and user even though they are stored globally. Client-supplied tenant/user IDs do not select another person’s bookings or progress.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
view | String | No | Trimmed, case-sensitive upcoming (default), calendar, or on_demand. Blank/unknown values fail rather than using the default. |
category | String | No | Trimmed exact category ID, blank means all. Accepted: general, getting_started, jobs, assets_stock, advanced, scheduling, assets, stock, finance, forms, reports. Returned categories always includes the complete list, not only matching categories. |
from / to | Unix seconds | For calendar | Integer-converted positive from and strictly later to; maximum span is 93×86400 seconds. Filters exclusive overlap: starts_at < to and ends_at > from. No parsing of civil dates or milliseconds. Ignored in other views. |
sort | String | On-demand only | Exact newest (default), az or za; unrecognized values fail only in on_demand. Orders respectively by recording_published_at descending/ID descending, title/ID ascending, or title descending/ID ascending. |
page | Integer | No | On-demand only: present non-null page enables zero-based pagination; negative values clamp to zero and nonnumeric values integer-convert to zero. Omission means first 200 records, not a default ten-row page. |
page_length | Integer | With page | On-demand page length defaults to 10 when page is set, then clamps to 1–200. Ignored without page. Upcoming/calendar cannot be paged through these controls. |
Example request
$result = FM_api('Training_list', [
'view' => 'calendar',
'category' => 'jobs',
'from' => '1794355200',
'to' => '1794614400',
]);
Example response
{
"data": [
{
"id": 1042,
"webinar_id": 91,
"title": "Jobs from start to finish",
"description": "Create and schedule jobs with Fieldmotion.",
"category": "jobs",
"category_name": "Jobs",
"image_url": "https://example.test/training.webp",
"image_alt": "Fieldmotion Training",
"presenter": "Fieldmotion trainer",
"starts_at": 1794477600,
"ends_at": 1794481200,
"timezone": "Europe/Dublin",
"status": "scheduled",
"capacity": null,
"registration_closes_at": 0,
"registration_open": true,
"registration_url": "https://example.test/register",
"interested": false,
"registration_opened_at": 0,
"join_available": false,
"join_url": "",
"registration_state": "none",
"provider_mapped": false,
"provider_available": false,
"recording_provider_mapped": false,
"recording_registration_state": "none",
"recording_duration": 0,
"watched_seconds": 0,
"recording_available": false,
"recording_url": "",
"recording_published_at": 0
}
],
"categories": [
{
"id": "general",
"name": "General"
},
{
"id": "getting_started",
"name": "Getting Started"
},
{
"id": "jobs",
"name": "Jobs"
},
{
"id": "assets_stock",
"name": "Assets & Stock"
},
{
"id": "advanced",
"name": "Advanced"
},
{
"id": "scheduling",
"name": "Scheduling"
},
{
"id": "assets",
"name": "Assets"
},
{
"id": "stock",
"name": "Stock"
},
{
"id": "finance",
"name": "Finance"
},
{
"id": "forms",
"name": "Forms"
},
{
"id": "reports",
"name": "Reports"
}
],
"total": 1
}
Each session object includes integer id/webinar_id, Unix-second starts_at/ends_at, stored timezone, title/description/category/category_name, image_url/image_alt/presenter, session status, nullable capacity and integer registration_closes_at. Unknown category values normalize to general. Descriptions are returned as text values without HTML sanitization; render them as text, as CRM2 does.
Action/state fields are registration_open, registration_url, interested, registration_opened_at, join_available, join_url, registration_state, provider_mapped, provider_available, recording_provider_mapped, recording_registration_state, recording_duration, watched_seconds, recording_available, recording_url and recording_published_at. Flags are booleans, durations/times/counts are integers, and URL/state fields are strings. Unavailable URLs are empty strings, not omitted.
A provider-mapped live session requires cached registration_state=confirmed for joining; a legacy unmapped session requires local interested=true. The session must be scheduled, current time must be at least starts_at−900 and no later than ends_at, and the chosen personal/legacy join URL must be valid HTTPS without embedded credentials. Joining is not exposed earlier by get/list.
Recordings require completed session status, published recording status, and ends_at no later than now. Mapped recordings expose no shared recording_url: use Training_watch for personal access. Unmapped recordings expose a valid HTTPS URL. A recording can be available without live interest or a live booking. Images also require valid HTTPS without embedded credentials.
Returns data, the full categories array, and integer total before row limits/paging. No matches means data=[], total=0. Only on_demand adds stale/unavailable refresh flags; the example is a legacy URL-based calendar record before its join window.
Errors and unusual responses
| Response | Condition |
|---|---|
{"error":"not logged in"} | No authenticated tenant context is available. Invalid signed credentials can be rejected by the dispatcher before the handler runs. |
{"error":"invalid Training view"} | view is not upcoming/calendar/on_demand. |
{"error":"invalid Training category"} | Nonblank category is not in the category allowlist. |
{"error":"invalid Training calendar range"} | Calendar endpoints are invalid, reversed/equal, or more than 93×86400 seconds apart. |
{"error":"invalid Training sort"} | Unknown on-demand sort value. |
Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.
Behaviour and edge cases
- Every view requires the parent webinar to be published. Upcoming selects scheduled sessions whose ends_at is later than now, including sessions already in progress; it returns at most 200 ordered by starts_at then ID ascending. Calendar uses scheduled sessions overlapping the supplied range, including past sessions in that range, capped at 500 with the same ordering.
- On-demand selects completed sessions already ended with published recordings, then requires a positive recording broadcast ID or a stored URL matching the SQL https:// prefix. With no provider schema only URL-based recordings qualify. This SQL prefilter is weaker than final URL validation: a malformed prefixed URL can be counted/listed but have recording_available=false.
- The total can exceed the returned count. Upcoming/calendar have no offset cursor; use narrower calendar windows when hitting their fixed caps. On-demand pages are offset-based, not stable snapshots.
- registration_open requires scheduled status, a future start, an unexpired/nonexistent registration cutoff, and either a provider broadcast mapping or valid registration URL. capacity is informational here; no local seat count/capacity enforcement occurs. A mapped row can therefore report registration_open=true even if its legacy registration_url is blank; use Training_register.
- Provider workflows require the global provider schema (migration 011) and server WebinarGeek credentials. This is deployment configuration, not the account’s HR setting or a request-supplied API key. Without the provider schema, legacy URL-based catalogue/interests still work; without credentials, provider actions fail while cached catalogue data remains readable.
- Refresh operates on all saved provider registrations for the authenticated user, not only the displayed category/page. Rows synced less than about five minutes ago are reused. Older rows are reconciled against provider subscriptions (up to 20 pages of 100); at most ten extra subscription-ID lookups recover entries omitted from provider lists. Cached statistics are retained when refresh fails.
stalereports incomplete refresh andunavailablereports missing provider schema/configuration; these are not booking states or proof of live provider health.
Side effects
- Upcoming/calendar only read catalogue and cached personalization. On-demand may contact WebinarGeek and update global registration status, personal URLs, monotonic watch/replay seconds and sync/edit timestamps; it does not create subscriptions.
See it in Fieldmotion
CRM1
No direct CRM1 caller for Training_list was found. The current catalogue/booking screen is CRM2 Training; tests are not production UI callers. No direct mobile-app or m-service caller for these CRM routes was found.
CRM2
Open Training Home or Upcoming Live Webinars; filter Network requests for Training_list. Home and list view request upcoming; Calendar View sends account-timezone-derived Unix from/to values and category. Watch Training Videos uses the Training_videosTable wrapper instead.
Related endpoints
Training_get: load one session and its protected actions.Training_videosTable: on-demand catalogue in the CRM2 table envelope.Training_mySessions: current-user interests or provider bookings instead of the shared catalogue.