Skip to content

Web Server API

The Rondo Sync web server (Fastify on port 3000) exposes a programmatic API for triggering syncs from external systems like Rondo Club.

API endpoints use a shared API key, separate from the dashboard session auth.

Header: X-Sync-API-Key: {key}

The key is set via the SYNC_API_KEY environment variable on the sync server. Generate one with:

Terminal window
openssl rand -base64 32
ScenarioStatusResponse
Missing header401{ ok: false, error: "Missing X-Sync-API-Key header" }
Invalid key403{ ok: false, error: "Invalid API key" }
Key not configured on server503{ ok: false, error: "API key not configured on server" }

GET /health and GET /health/sync are public and require neither API-key nor dashboard-session authentication.

RoutePurposeResponse
/healthDashboard server availabilityHTTP 200, { "status": "ok", "timestamp": "…" }
/health/syncAggregate completed-run coverage of configured schedulesHTTP 200, { "status": "ok" }, or HTTP 503, { "status": "overdue" }

Sync health allows one hour of grace for interval jobs and four hours for other jobs. The latest completed run must have started at or after the due slot at that cutoff. Both success and partial count; a running job alone does not. Disabled/manual schedules and changed schedules before their first eligible slot are exempt. The response contains no pipeline or member details. See Error monitoring for GlitchTip reporting and Twelve’s schedule handling.

Syncs a single member from Sportlink to Rondo Club. Launches a Playwright browser session to fetch fresh data from Sportlink (person details, parents, functions, committees, and free fields), then syncs the member to WordPress. First, a targeted SearchMembers query looks up the exact KNVB ID with union team data enabled; an absent active match is retried with the inactive-member filter. The partial /general response is overlaid on this fresh result, so KernelGameActivities and AgeClassDescription no longer wait for the next bulk import. A missing or ambiguous member, an incomplete activity/age-class response, or a failed search aborts before person updates; an explicitly empty activity clears the previous value. Search navigation retries a stuck panel once and can refresh an expired session. Fresh parent data overrides the member’s record from the latest full snapshot before parent deduplication, so a newly added parent is created or updated immediately and linked to the child in both directions. Other snapshot members remain available so shared parents retain links to siblings.

Rate limit: 5 requests per minute.

Concurrency: Only one individual sync can run at a time (Sportlink uses TOTP, so only one Playwright session is possible).

{
"knvb_id": "12345678"
}
FieldTypeRequiredDescription
knvb_idstringYesKNVB member ID (4-10 alphanumeric characters, e.g. SYQG014)

Success (200)

{
"ok": true,
"knvb_id": "12345678",
"action": "updated",
"rondo_club_id": 456
}
action valueMeaning
createdNew person created in Rondo Club
updatedExisting person updated
skippedNo changes detected (member already up to date)

Errors

StatusConditionResponse
400Invalid or missing knvb_id{ ok: false, error: "Invalid knvb_id: must be 4-10 alphanumeric characters" }
422Member not found in Sportlink data{ ok: false, error: "Member not found" }
429Another sync already running{ ok: false, error: "Another individual sync is already in progress. Try again in a minute." }
500Internal error{ ok: false, error: "Internal sync error" }
Terminal window
curl -X POST https://sync.example.com/api/sync/individual \
-H 'Content-Type: application/json' \
-H 'X-Sync-API-Key: your-api-key-here' \
-d '{"knvb_id":"12345678"}'

Add to the sync server’s .env:

Terminal window
SYNC_API_KEY=your-generated-key-here

After adding the key, restart the web server:

Terminal window
systemctl restart rondo-sync-web

The same key must be configured in Rondo Club’s .env so WordPress can call this endpoint.

Pipeline history and manual starts use dashboard session authentication, not X-Sync-API-Key. Since Rondo Sync 0.16.1, the overview, route validation and display names share PIPELINE_CONFIG from lib/dashboard-queries.js, including Twelve. Unknown pipeline names return 404; unauthenticated requests redirect to /login.

  • GET /pipeline/:name: run history, 20 runs per page. page must be a positive integer or the route returns 400. Twelve history is /pipeline/twelve.
  • POST /api/pipeline/:name/start: launches scripts/sync.sh for that pipeline. Twelve launches with ['twelve'], so this is a manual run outside the scheduled window checks. Success returns { ok: true, pipeline: "twelve" }; an already running pipeline returns 409. Immediate launch failures return 500 and retain a per-launch log under logs/dashboard-launch/.

A successful launch response does not establish that the import completed; check the tracked run and its outcome. See Twelve pipeline for reconciliation and checkpoint rules.

GET /beheer/schedules and POST /beheer/schedules use dashboard session authentication. The POST requires the form’s session CSRF token and current configuration revision: missing/wrong CSRF returns 403, validation returns 400 with the draft preserved, and a stale revision returns 409. A valid save redirects to /beheer/schedules?saved=1. This form does not use X-Sync-API-Key. See Editable Sync Schedules for fields, allowed cadences and dispatcher behavior.