Your first activity.
Go from an original FIT file to decoded JSON and a verified copy of the source. This example runs on your computer or server with Node.js 22 or later. No packages are required.
Before you begin#
You need access to an enabled MovePacket beta environment, an API key for that environment, and a FIT activity file no larger than 4 MiB. Keep the key in your secret manager or server environment as MOVEPACKET_API_KEY. Never put it in browser code or a URL.
For a test without personal data, download the synthetic sample ride. It contains generated cycling data, not a real athlete's ride.
Run the complete example#
Download movepacket-quickstart.mjs and save it beside your FIT file. Set the API origin supplied with your beta access. For the local development preview, use http://127.0.0.1:8787.
export MOVEPACKET_API_URL="https://movepacket.com"
# Supply MOVEPACKET_API_KEY through your secret manager or environment.
node movepacket-quickstart.mjs ride.fit ./ride-data
Choose an output directory that does not already exist. The example uploads the file, polls for completion, downloads the decoded data and original, and compares the original's SHA-256 against both your input and the API checksum. It saves activity.json and original.fit only after verification.
If processing takes more than two minutes, the example returns the activity ID so you can check it again. A local timeout does not cancel processing. Transient request failures are retried up to three attempts. Re-uploading identical bytes within the same workspace reuses the activity.
Upload the file#
You can also follow the flow one request at a time. Send the raw file body, not a multipart form or JSON wrapper.
curl --fail-with-body "$MOVEPACKET_API_URL/v1/activities" \
-H "Authorization: Bearer $MOVEPACKET_API_KEY" \
-H "Content-Type: application/vnd.ant.fit" \
--data-binary @ride.fit
An accepted upload normally returns HTTP 202. Save its id. Responses include links to the status, original, and decoded data. The IDs and checksum below are illustrative.
{
"id": "act_00000000-0000-4000-8000-000000000001",
"status": "queued",
"sha256": "0000000000000000000000000000000000000000000000000000000000000000",
"byte_size": 25000,
"error_code": null,
"created_at": "2026-09-16T12:00:00.000Z",
"duplicate": false,
"links": {
"self": "/v1/activities/act_00000000-0000-4000-8000-000000000001",
"original": "/v1/activities/act_00000000-0000-4000-8000-000000000001/original",
"data": "/v1/activities/act_00000000-0000-4000-8000-000000000001/data"
}
}
Wait for ready#
Use the returned ID as ACTIVITY_ID. Poll this endpoint every few seconds until status is ready or failed.
curl --fail-with-body "$MOVEPACKET_API_URL/v1/activities/$ACTIVITY_ID" \
-H "Authorization: Bearer $MOVEPACKET_API_KEY"
A successful status request returns HTTP 200 even while processing continues. The status field determines whether the decoded data is ready. A failed activity includes an error_code; its original remains retrievable.
Retrieve the result#
curl --fail-with-body "$MOVEPACKET_API_URL/v1/activities/$ACTIVITY_ID/data" \
-H "Authorization: Bearer $MOVEPACKET_API_KEY" \
--output activity.json
curl --fail-with-body "$MOVEPACKET_API_URL/v1/activities/$ACTIVITY_ID/original" \
-H "Authorization: Bearer $MOVEPACKET_API_KEY" \
--output original.fit
The complete Node.js example verifies file integrity automatically. For your own integration, compare the downloaded original's SHA-256 with the upload response and your source file. Continue with processing and reliability and the data model.