[New] Timesheet Approval Status API

Summary

We’re introducing a new set of endpoints that let you programmatically manage weekly timesheet approval workflows in Asana.

With this release, you can:

  • Read and manage timesheet approval statuses for any user on a per-week basis (Monday-Sunday UTC)
  • Transition timesheets through approval states: DRAFTSUBMITTEDAPPROVED (or REJECTED)
  • Filter time tracking entries by their associated timesheet approval status
  • Set description and billable_status on time tracking entries

Note: description and billable_status on time tracking entries requires the Timesheets & Budgeting add-on (TBAO).

This enables teams to build automated timesheet submission, validation, approval, and reporting workflows via the API.

Timeline

These endpoints are now available!

Usage

New resource: Timesheet Approval Status

Each timesheet_approval_status represents one user’s weekly timesheet (Monday–Sunday UTC). The resource has the following shape:

Field Type Description
gid string Globally unique identifier
user UserCompact The user who submitted the timesheet
workspace WorkspaceCompact The workspace the timesheet belongs to
start_date date Start of the timesheet week (Monday, UTC)
end_date date End of the timesheet week (Sunday, UTC)
approval_status enum One of: DRAFT, SUBMITTED, APPROVED, REJECTED
created_at datetime When the timesheet record was created

New endpoints

Get a single timesheet approval status

GET /timesheet_approval_statuses/{timesheet_approval_status_gid}

List timesheet approval statuses (with filters)

GET /timesheet_approval_statuses

Query parameters:

Parameter Type Required Description
workspace string Yes Workspace GID
user string Conditional User GID. Required when filtering by dates or statuses.
from_date date Yes Filters to timesheets with start_date ≥ this value
to_date date No Filters to timesheets with start_date ≤ this value
approval_statuses string No Comma-separated list (e.g., submitted,approved)

Example: retrieve a user’s submitted and approved timesheets for a date range:

// GET /timesheet_approval_statuses?user=123&workspace=456&from_date=2025-03-10&to_date=2025-03-16&approval_statuses=submitted,approved
{
  "data": [
    {
      "gid": "890",
      "resource_type": "timesheet_approval_status",
      "user": { 
"gid": "123", 
"resource_type": "user" 
},
      "workspace": { 
"gid": "456", 
"resource_type": "workspace" 
},
      "start_date": "2025-03-10",
      "end_date": "2025-03-16",
      "approval_status": "SUBMITTED",
      "created_at": "2025-03-16T01:00:00Z"
    }
  ]
}

Create or retrieve a timesheet approval status

Use this endpoint to get-or-create a weekly timesheet. If a record already exists for the given user, workspace, and week, it is returned.

// POST /timesheet_approval_statuses
{
  "data": {
    "user": "123",
    "workspace": "456",
    "start_date": "2025-03-10",
    "end_date": "2025-03-16"
  }
}

Update a timesheet approval status

Transition a timesheet to a new approval state. The server enforces valid state transitions and domain mode (e.g., submit-only vs. submit-and-approve). You can optionally include a message that will be recorded as a story on the transition.

// PUT /timesheet_approval_statuses/{timesheet_approval_status_gid}
{
  "data": {
    "approval_status": "APPROVED",
    "message": "Looks good — approved for the week."
  }
}

Updated endpoints

Filter time tracking entries by timesheet

The existing GET /time_tracking_entries endpoint now accepts a timesheet_approval_status_gid parameter. This returns all time tracking entries matching the user and date range of the specified timesheet.

GET /time_tracking_entries?timesheet_approval_status_gid=890

New optional fields on time tracking entries (TBAO only)

POST /tasks/{task_gid}/time_tracking_entries and PUT /time_tracking_entries/{time_tracking_entry_gid} now support two additional optional fields:

Field Type Description
description string A text description for the time entry
billable_status enum Whether the entry is billable or non-billable

Example: create a time tracking entry with description and billable status:

POST /tasks/{task_gid}/time_tracking_entries
{
  "data": {
    "entered_on": "2025-03-12",
    "duration_minutes": 120,
    "description": "Client review meeting and follow-up notes",
    "billable_status": "billable"
  }
}

Resources

Thanks, and feel free to reply to this post with questions!

2 Likes