Get tracked hours for an opportunity
Hours each expert worked on this opportunity, one row per person and date. Time spent on your other opportunities, and time clocked in but not spent on work, is not included. The current day is partial and refreshes through the day; last_updated_at says when the hours were last refreshed.
Authorization
apiKey API key as Bearer token: Authorization: Bearer
In: header
Path Parameters
ID of the opportunity, as returned by POST /opportunities or GET /opportunities.
Query Parameters
Start of the window, inclusive: an ISO 8601 UTC timestamp such as 2026-09-08T00:00:00Z, or a bare 2026-09-08 read as midnight UTC. A person's day counts when the instant it opened in their own tracker timezone falls in the window, so a day is never returned in halves.
End of the window, exclusive, in the same UTC form: a day that opened exactly at to belongs to the next window, so consecutive requests neither double count nor skip. At most 92 days after from.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X GET "https://terac.com/api/external/v2/opportunities/string/hours?from=string&to=string"{
"last_updated_at": "string",
"total_seconds": 0,
"total_hours": 0,
"data": [
{
"participant_id": "string",
"submission_id": "string",
"email": "string",
"date": "string",
"timezone": "string",
"seconds": 0,
"hours": 0
}
]
}{
"code": "BAD_REQUEST",
"message": "Invalid input data",
"issues": []
}{
"error": {
"code": "UNAUTHORIZED",
"message": "API key required. Include Authorization: Bearer <key> header."
}
}{
"error": {
"code": "FORBIDDEN",
"message": "This account is not permitted to use the API."
}
}{
"code": "NOT_FOUND",
"message": "Not found",
"issues": []
}{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Retry after 61 seconds."
}
}{
"code": "INTERNAL_SERVER_ERROR",
"message": "Internal server error",
"issues": []
}Reject a submission POST
Rejects a submission that is `awaiting_review`, so the expert is not paid for that work and the submission becomes `rejected`. `rejection_category` and `rejection_reason` are optional, but they are the only record of why the work went unpaid. A submission in any other status returns 409.
Get tracked hours for one submission GET
Hours this submission's participant worked on its opportunity, one row per date. Time spent on your other opportunities, and time clocked in but not spent on work, is not included. The current day is partial and refreshes through the day; `last_updated_at` says when the hours were last refreshed. Returns exactly this submission's participant's rows from the opportunity response for the same range.