update_athletes() replaces external properties,
updating with a position, sport,
dob or height column now removes any external
property of that name from the athlete. If an athlete still has one,
get_athletes() returns it as a suffixed column such as
position.1; that column is not sent, and a warning says so.
Copy any value you want to keep into the native column first.create_athletes() and update_athletes()
now write the athlete profile fields position,
sport, dob and height as native
API fields. Previously a column with one of these names was sent as an
external (custom) property of the same name.
dob accepts "YYYY-MM-DD", a 4-digit year
("1998" or 1998), a Date, or a
POSIXct. Date-times are sent as the calendar date in their
own time zone, never shifted to UTC.height is in centimeters and is rounded to 1 decimal
place. A warning is raised when a height below 100 is sent, because the
API reads those values back as legacy feet or inches (95 reads back as
241.3).NA or blank value is not sent. On update the field
is left unchanged; the API cannot clear these fields, so clear them in
the Hawkin app.get_athletes() can be passed back to
update_athletes() (or create_athletes())
without adding junk external properties. lastTestedOn is
read-only and is never sent, and create_athletes() no
longer sends an id column as an external property.update_athletes() always
sent an external field, empty ([]) when the
data frame had no custom-property columns. The API replaces external
properties on update, so an update that only changed, say,
name or active could delete every custom
property on those athletes. external is now only sent for
an athlete with at least one non-NA, non-blank custom
value, and always as a JSON object. With no custom columns, or with
every custom cell NA or blank, the athlete’s custom
properties are left unchanged. create_athletes() follows
the same rule.create_athletes() and update_athletes()
sent a teams or groups list column nested one
level too deep ([["t2","t3"]]), and sent a comma-separated
string such as "t2,t3" as one ID. Both are now sent as a
flat array of IDs: a list column element is flattened, and a string is
split on , and trimmed, as the Sheets and Excel add-ins do.
A single ID is still sent as an array. NA,
NULL or blank values are not sent (on update, the athlete’s
teams or groups are left unchanged); previously a NULL list
element was sent as [{}].NA and blank custom-property values are no longer sent
as external properties. A list-valued custom-property column now sends
one string per athlete (several values joined with ,) and
skips NULL or empty elements, which were previously sent as
[{}] or [[]] and replaced the athlete’s real
custom properties on update.Tagged in the monorepo on 2026-09-30 but not submitted to CRAN; these changes reach CRAN in 2.2.0.
get_tests() gains three optional arguments that map to
the Hawkin API v1.16 response-shape query params: useNulls
(default TRUE), rounding (default
FALSE) and nestMetrics (default
FALSE). Only a non-default value is sent, so existing calls
produce identical requests. They exist so customers migrating from a
legacy named API endpoint to /api/v1 can reproduce that
endpoint’s payload; new integrations should leave the defaults.
useNulls = FALSE keeps the string "N/A"
for non-calculable metrics instead of NA (affected metric
columns become character).rounding = TRUE returns each metric rounded to its
standard display precision. Inert when
nestMetrics = TRUE.nestMetrics = TRUE returns a long table — one row per
test and metric with metric_id, metric_label,
metric_units and metric_value columns beside
the trial, athlete and test-type columns. A test with no numeric metrics
keeps a single row with NA metric fields.get_tests() could silently
return incomplete data. If any page after the first failed (a non-200
status such as 401, 429 or 500, a network error, or a pagination cursor
that did not advance), the function logged a warning, stopped paginating
and returned only the pages fetched so far. The result looked like a
valid, complete data frame. get_tests() now stops with an
error naming the status and page, and no partial result is returned. A
200 response whose body can’t be parsed is also reported with the
failing page. Transient failures (HTTP 429, 502, 503, 504) are retried
up to three times with backoff before the error is raised.get_forcetime() built its
data frame by indexing the API response positionally rather than by
field name. When the response elements did not line up with the assumed
positions, the force-time series were populated from the wrong fields,
leaving column values misaligned relative to their labels (for example,
a force series appearing under the time_s column). Because
the shape and length of the data were unaffected, the result looked
valid and no error was raised, so downstream analysis could be silently
incorrect. Columns are now selected by their API field names
(Time(s), LeftForce(N),
RightForce(N), …), so each series is populated from the
correct vector regardless of field order or omitted optional fields. The
tri-axial force and moment columns are handled the same way.get_forcetime() now reads testType_id from
the named testType$id field instead of a positional
lookup.testType_id), which previously had no test
coverage.get_tests() now uses cursor-based API pagination
instead of time-window chunking. The chunk_size argument is
deprecated and ignored.includeInactive filtering in get_tests()
is now server-side (API v1.13). Behavior is unchanged but the parameter
is sent to the API directly rather than filtering client-side.HawkinForceTime property renamed:
testType_canoncical -> testType_canonical
(typo fix).get_cop() — retrieve raw Center of Pressure (COP)
time-series data for a test, returning a new HawkinCOP
object with the six COP series (cop_x, cop_y,
left_cop_x, left_cop_y,
right_cop_x, right_cop_y). Exclusive to the
Free Run test type (other types return a 404). COP values are kept as
NA for samples with no weight on a given plate.update_athletes() now
correctly calls UpdateAthleteJSON() instead of
AddAthleteJSON(). Previously, update payloads were missing
the required id field.create_athletes() and update_athletes()
now return the failure data frame when operations partially fail, as
documented.stop(logger::log_error(...)) antipattern in
create_athletes(), update_athletes(), and
UpdateAthleteJSON().@examples syntax in
create_athletes() and update_athletes()
documentation.get_forcetime().get_forcetime() no longer returns NULL for
tests whose API response omits an rsi value. A
return(NULL) inside a tryCatch({}) block was
escaping the whole function instead of the block, so any non-RSI test
(and every get_forcetime_bulk() item) silently came back
empty.TestTypePrep().AthletePrep() now selects athlete columns by name and
unnests external (custom) properties robustly, handling both uniform
sub-data-frames and list-columns whose keys vary across athletes.
Athletes missing a given key receive NA instead of
triggering an error in get_athletes() /
get_tests().NA-safe. A missing or
non-POSIXct expiration returns a clear prompt to run
hd_connect() rather than
missing value where TRUE/FALSE needed, via the internal
token_seconds_remaining() helper used across all data
functions.get_athletes() now returns the API v1.14 athlete
profile fields (image, position,
dob, sport, height,
lastTestedOn) when present in the response.get_tests() now returns the athlete profile fields
(athlete_image, athlete_position,
athlete_dob, athlete_sport,
athlete_height, athlete_lastTestedOn) when
present.get_forcetime_bulk() now accepts a data frame with an
id column (e.g., output of get_tests()) in
addition to a character vector of test IDs.get_forcetime_bulk() now supports .rda
export format.hd_auth_store() with security note about
.Rhistory risk when passing tokens as arguments.update_athletes() @return
documentation to say “updated” instead of “created”.Addition of org_name to get_access()
parameters.
Improved functionality to get_tests() to accept
character strings in the format “YYYY-MM-DD” for from and
to
Addition of ‘Metric Library’ returned from
get_metrics()
Changes to get_tests() metric headers. Improved
consistency of naming reflective of the metric library
Improved functionality for get_forcetime() to return
all test types
Update of get_tests() functionality.
Depreciation of get_tests_... functions.
‘teamId’ and ‘groupId’ parameters now accept lists and atomic vectors to go along with single text strings
Addition of logs functionality and customization
Updated documentation
fix to DateTimeParam utility function
updated test files
to parameterget_tests.... Corrected pad_and_condense
function in utils.RBug fixes to get_tests_type. Now handles test trials
with and without tags specified
Changes to get_tests_type. ‘typeId’ parameter now
accepts strings containing either canonical test Id, test type name, or
test type abbreviation. See docs for abbreviations.
Addition of get_tags function. Create data frame of
tags within your system, including: id, name, description.
Addition of utils.R file with utility functions to minimize code and increase readability.
get_tests_... function outputs now include tag Ids, names,
and description columns with the prefix ‘test_type_tag_’. These can be
found after ‘test_type_canonicalId’ column.get_tests_... functions to handle NULL
externalIdsUpdates to all get_tests_... functions to include
filter parameter for ‘active’ tests. Ability to include or exclude
disabled trials.
Updates to all get_tests_... functions to include
‘sync’ parameter. Ability to utilize ‘syncFrom’ and ‘syncTo’ in all
queries. This allows for more efficient queries and faster download
times when used frequently or to maintain an external database.
Bug fixes to externalId field
get_athlete output to include externalIdbug fixes to get_tests_team and
get_tests_group
Changes to column name outputs for get_tests...
calls.
bug fixes to get_forcetime