RugbyMetrics Connect
Connect is how a GPS or wearable system, or a club's own script, sends a training or match session straight into RugbyMetrics. One JSON request, no file to export. The data lands in the same place a GPS file import does, so every GPS screen in RugbyMetrics shows it.
What it is
- One request per session: the session, then one entry per athlete with the numbers the system measured.
- It writes into the same tables as the GPS file import. Nothing changes in the app for the coach.
- It is for clubs on a paid plan. A club administrator makes the keys.
- Adults only: RugbyMetrics is for players aged 18 or over.
Authentication
A club administrator opens Team settings in the app, goes to RugbyMetrics Connect and makes a key. The key looks like rmk_ followed by 40 characters. It is shown once. RugbyMetrics keeps only a fingerprint (SHA-256) and the first 12 characters so you can tell keys apart, and an administrator can revoke a key at any time. A key can do one thing: write device sessions for its own club and team.
Send the key on every request:
Authorization: Bearer rmk_YOUR_KEYPlayers are mapped, never created
Your system names its athletes with its own ids. In Team settings the club says which RugbyMetrics player each id is (system name plus id). A request that contains an id that is not mapped is refused with 400 and a list of the unknown ids. Connect never creates a player from device data.
Request
POST https://app.rugbymetrics.com/api/connect/v1/sessions with a JSON body. Times are ISO 8601 with an offset, for example 2026-10-20T19:00:00+02:00. A session can last at most 200 minutes and a request can hold at most 100 athletes.
| Field | Type | Required | Meaning |
|---|---|---|---|
vendor | string | yes | Your system's name: 1 to 30 letters, digits, dots, dashes, underscores. Stored in lower case. The mapping of athlete ids is per vendor. |
session.external_id | string | yes | Your id for the session, 1 to 64 characters. The same vendor and external_id again updates that session and never creates a second one. |
session.start, session.end | string | yes | ISO 8601 with offset. End after start. The session date is the start's date in the team's time zone; the duration is end minus start. |
session.type | string | yes | training or match. |
session.fixture_id | string | no | The id of a RugbyMetrics match of the key's team, to show the numbers in that match's report. |
athletes[].vendor_athlete_id | string | yes | The athlete's id in your system (1 to 64 characters), once per request. |
athletes[].metrics | object | no | Any of the metrics below. All are optional. A metric that is left out, or null, is stored as no value. |
Metrics (units are fixed)
| Metric | Unit | Accepted range | Notes |
|---|---|---|---|
distance_m | metres | 0 to 20000 | Total distance covered in the session. |
hsr_m | metres | 0 to 20000 | High-speed running distance. |
sprint_m | metres | 0 to 20000 | Sprint distance. |
sprints | count | 0 to 500, whole number | Number of sprints. |
max_speed_ms | metres per second | 0 to 12.5 | Top speed. 12.5 m/s is the highest value accepted. |
accels | count | 0 to 2000, whole number | Number of accelerations. |
decels | count | 0 to 2000, whole number | Number of decelerations. |
player_load | arbitrary units | 0 to 5000 | The vendor's player load figure. |
hr_avg | beats per minute | 30 to 230, whole number | Average heart rate. Stored only for players with a wellness consent. |
hr_max | beats per minute | 30 to 250, whole number | Maximum heart rate. Stored only for players with a wellness consent. |
impacts | count | 0 to 2000, whole number | Number of impacts. |
A value outside its range is refused with a field-level 400; nothing from that request is stored. Unknown metric names are refused too, so a typo is caught instead of silently lost.
Example
curl -X POST https://app.rugbymetrics.com/api/connect/v1/sessions \
-H "Authorization: Bearer rmk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"vendor": "catapult",
"session": {
"external_id": "S-2026-10-20-AM",
"start": "2026-10-20T19:00:00+02:00",
"end": "2026-10-20T20:30:00+02:00",
"type": "training"
},
"athletes": [
{ "vendor_athlete_id": "A1", "metrics": { "distance_m": 5200, "hsr_m": 400, "max_speed_ms": 9.1, "hr_avg": 142 } },
{ "vendor_athlete_id": "A2", "metrics": { "distance_m": 4800, "impacts": 31 } }
]
}'Answer 201 (session created) or 200 (session updated):
{
"ok": true,
"session": "created",
"athletes_matched": 2,
"rows_created": 2,
"rows_updated": 0,
"rows_written": 2,
"metrics_stored": 6,
"hr_values_dropped": 0,
"skipped_no_data_consent": []
}Answer 400 when something is wrong. Every error names its field:
{
"ok": false,
"errors": [
{ "field": "athletes[1].vendor_athlete_id", "message": "Unknown athlete id \"A9\" for vendor \"catapult\". Map it to a player in RugbyMetrics ..." }
],
"unknown_athlete_ids": ["A9"]
}Consent
- Heart rate (
hr_avg,hr_max) is health data. It is stored only for players who have given the wellness consent. For the others the two fields are dropped, the rest of their numbers are stored, and the answer says how many values were dropped (hr_values_dropped). - All other numbers need the player's data consent. A player without it is skipped and named in
skipped_no_data_consent. - A player can withdraw a consent at any time. Withdrawing affects later requests.
Status codes
| Code | When |
|---|---|
201 | The session was created and the athletes' rows were written. |
200 | The session already existed and was updated (idempotent re-send), or a /validate request passed. |
400 | The body is not valid JSON, a field is missing or out of range, an athlete id is not mapped, or the match is not the team's. The errors list has one entry per problem with its field and a message. |
401 | No key, a malformed key, an unknown key or a revoked key. |
403 | The club is not on a paid plan, or the organisation is read-only (scheduled for deletion). |
405, 404 | Not a POST, or not one of the two paths. |
413 | The body is larger than 256 KB. |
429 | More than 60 requests in a minute with the same key. The answer has Retry-After: 60. |
503 | Temporarily unavailable. Send the same request again; sending it twice is safe. |
Connect Verified: the self-test
POST https://app.rugbymetrics.com/api/connect/v1/validate takes the same body and the same key, checks everything (shape, ranges, athlete ids, match, consents) and writes nothing. It returns 200 with the counts it would have written, or the same 400 list. Device makers can run it against a club's test setup to show that their integration sends valid sessions. A validate request counts toward the 60 requests a minute.
Versioning promise
This is version 1. In v1 a field never changes meaning, a unit never changes, and a range is never narrowed. New fields can be added; they are optional and ignored by clients that do not send them. A breaking change would be a new path (/api/connect/v2) and v1 would keep working.
What RugbyMetrics keeps
The numbers go into the club's GPS data, like a file import. For each request RugbyMetrics logs the first 12 characters of the key, the time, the result code and the number of athletes. The content of the request is not logged, and the log is deleted after 30 days. See the Privacy Policy.
Machine-readable description
The OpenAPI 3.1 file is at /connect/openapi.json.
Questions, or a device system you would like us to test with: [email protected].