Get started
Quickstart
Make your first HubFit API request in five minutes: create an API key, list the check-ins awaiting review, read one and review it.
In HubFit, go to Settings > API and create a key. Name it after what will use it, such as "Check-in dashboard", choose its permissions (for this guide, Read clients and Review check-ins) and when it expires.
Copy the key straight away: HubFit shows it once. Keys start with hubfit_sk_. Only the workspace's owner can create them.
Treat a key like a password. Keep it on your server, never in a website, a mobile app or a public repository.
export HUBFIT_API_KEY="hubfit_sk_4fJ9kQ2mX7pL3vR8tN6wZ1bYc5Hd0sGa2Ke7Uq9Wx3Mn"Send the key as a bearer token in the Authorization header. A 200 with a data list means you're connected; a 401 means the key is missing or wrong. See Authentication.
totalCount says how many match across every page. Keep the id of a submission for the next step.
curl -G https://api.hubfit.com/v1/check-in-submissions \
-H "Authorization: Bearer $HUBFIT_API_KEY" \
-d status=awaiting_reviewconst response = await fetch("https://api.hubfit.com/v1/check-in-submissions?status=awaiting_review", {
headers: {
Authorization: `Bearer ${process.env.HUBFIT_API_KEY}`,
},
});
const { data, nextCursor } = await response.json();import os
import requests
response = requests.get(
"https://api.hubfit.com/v1/check-in-submissions",
headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}"},
params={
"status": "awaiting_review",
},
)
page = response.json()
data, next_cursor = page["data"], page["nextCursor"]{
"data": [
{
"id": "6ad6af25540e6a26540ffd23",
"name": "Weekly check-in",
"status": "awaiting_review",
"client": {
"id": "6ad6af41d3199442d31b2743",
"name": "Jordan Miller"
},
"submittedAt": "2026-10-26T14:32:05.000Z",
"checkInDate": "2026-10-26",
"reviewedAt": null,
"reviewedBy": null
}
],
"nextCursor": "eyJpZCI6IjZhZDZhZjNmMjljNTk3ZjE1In0",
"totalCount": 48
}Get the submission by its id to read the client's answers. Each answer has a type, such as text, metric or yes_no, that decides its other fields.
curl https://api.hubfit.com/v1/check-in-submissions/6ad6af25540e6a26540ffd23 \
-H "Authorization: Bearer $HUBFIT_API_KEY"const response = await fetch("https://api.hubfit.com/v1/check-in-submissions/6ad6af25540e6a26540ffd23", {
headers: {
Authorization: `Bearer ${process.env.HUBFIT_API_KEY}`,
},
});
const { data } = await response.json();import os
import requests
response = requests.get(
"https://api.hubfit.com/v1/check-in-submissions/6ad6af25540e6a26540ffd23",
headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}"},
)
data = response.json()["data"]{
"data": {
"id": "6ad6af25540e6a26540ffd23",
"name": "Weekly check-in",
"status": "awaiting_review",
"client": {
"id": "6ad6af41d3199442d31b2743",
"name": "Jordan Miller"
},
"submittedAt": "2026-10-26T14:32:05.000Z",
"checkInDate": "2026-10-26",
"reviewedAt": null,
"reviewedBy": null,
"reviewComment": "",
"answers": [
{
"question": "What went well this week?",
"type": "text",
"answer": "Hit every session and slept better."
},
{
"question": "How would you rate your energy, from 1 to 10?",
"type": "one_to_ten",
"answer": "8",
"value": 8
},
{
"question": "Your weight this morning",
"type": "metric",
"answer": "182.4",
"value": 182.4,
"unit": "lb",
"metricId": "6ad6af776298037662967079"
},
{
"question": "Did you hit your protein target every day?",
"type": "yes_no",
"answer": "Yes",
"answeredYes": true
}
]
}
}Mark the check-in reviewed. With a comment, HubFit sends it to the client by email and push, as reviewing in the app does, and it can't be taken back, so only send what you mean to.
The Idempotency-Key header makes a retry safe: send the same key again and you get the first response back instead of a second review. See Idempotency.
curl -X POST https://api.hubfit.com/v1/check-in-submissions/6ad6af25540e6a26540ffd23/review \
-H "Authorization: Bearer $HUBFIT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"comment": "Great week, Jordan. Keep the step count up."
}'const response = await fetch("https://api.hubfit.com/v1/check-in-submissions/6ad6af25540e6a26540ffd23/review", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HUBFIT_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
comment: "Great week, Jordan. Keep the step count up.",
}),
});
const { data } = await response.json();import os
import uuid
import requests
response = requests.post(
"https://api.hubfit.com/v1/check-in-submissions/6ad6af25540e6a26540ffd23/review",
headers={"Authorization": f"Bearer {os.environ['HUBFIT_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())},
json={
"comment": "Great week, Jordan. Keep the step count up.",
},
)
data = response.json()["data"]{
"data": {
"id": "6ad6af9094a2ea9194a47d8e",
"status": "reviewed",
"reviewedAt": "2026-10-26T14:32:05.000Z",
"clientNotified": true
}
}You've made authenticated reads and a write. From here:
- Add a webhook endpoint for
check_in_submission.created, so you hear about new check-ins instead of polling. - Read Errors and Rate limits before you go live, so your integration recovers on its own.
- Browse the API reference for every endpoint.
