Activities API Guide#

The Activities API enables you to programmatically retrieve a log of actions performed across your Workiva organization or within a specific workspace. Use it to build audit reports, feed activity data into external systems like a SIEM, track user logins, monitor permission changes, and satisfy compliance requirements.


Table of Contents#


Prerequisites & Authentication#

Before getting started, make sure you have credentials set up.

All requests to the Workiva API require:

  • A valid OAuth 2.0 Bearer token

  • The X-Version: 2026-01-01 header on every request

  • The appropriate OAuth scopes for each operation (noted per endpoint below)

  • An admin role on the organization or workspace you are querying (see Key Concepts)

export TOKEN="your_access_token_here"
export ORG_ID="your-organization-uuid"
export WORKSPACE_ID="your-workspace-id"

Important: Always include X-Version: 2026-01-01 on all requests. Mixing functionality between different API versions is not supported and may produce unpredictable results.


Key Concepts#

Concept

Description

Activity

A record of a single action performed in the Workiva platform, such as a user login, a role change, or a workspace setting update. Each activity includes the action type, who performed it, when it occurred, the outcome, and which resources were affected.

Activity Action

A descriptor for the type of action that produced an activity. Each action has a unique id (e.g., com.workiva.administration.workspace_membership.create) and a human-readable alias (e.g., workspace_membership_create). Use the alias field to identify activities relevant to your use case.

Performer

The user or system principal that performed the action. Includes displayName, uniqueName (email or username), id, ipAddress, and type.

Target

The resource affected by the action — for example, the user who was added to a workspace or the document whose permissions were changed. An activity can have multiple targets.

Outcome

The result of the activity action: success, failure, pending, or unknown.

Organization

The top-level container that owns all workspaces. Identified by a UUID (organizationId). Organization-level activities span all workspaces.

Workspace

A container within an organization that holds files and users. Workspace-level activities are scoped to actions taken within that workspace.

Required Admin Roles#

To access activities through the API, the authenticated user must hold one of the following roles:

Scope

Required Role

Organization activities

Org User Admin, Org Workspace Admin, or Org Security Admin

Workspace activities

Workspace Owner

Learn more about organization roles in the Workiva support documentation.


How Activities Work — The Pull Model#

Important: The Activities API is a read-only, pull-based API. There are no webhooks, no event streams, no push notifications, and no way to have Workiva send activity data to an external system such as an IdP, SFTP server, or SIEM automatically. Your application must poll the API on a schedule to retrieve new activity records.

This means that to build an ongoing audit log or feed activity data into an external tool like Splunk or SumoLogic, you need to:

  1. Poll the organization or workspace activities endpoint on a recurring schedule (e.g., every 15 minutes, hourly, or daily)

  2. Track the timestamp of the last activity you processed so that subsequent polls only retrieve new records

  3. Store or forward the retrieved activities to your target system

The guide section Building a Recurring Activity Export walks through this pattern in detail.

Note: Activities are also viewable in the Workiva platform UI and can be exported as CSV from Organization Admin or Workspace Settings. The API provides the same data in a structured JSON format suitable for programmatic consumption.


Retrieving Activities for an Organization#

Retrieve a paginated list of all activities across every workspace in an organization. This is the broadest view of activity data available.

Required scope: activity:read

GET /organizations/{organizationId}/activities

curl -X GET "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01"

Response (200 OK):

{
  "@nextLink": "<opaque_url>",
  "data": [
    {
      "id": "NjE0MjIxODIt...",
      "action": {
        "alias": "workspace_membership_create",
        "category": "Administration",
        "deprecated": false,
        "id": "com.workiva.administration.workspace_membership.create",
        "name": "Workspace membership created"
      },
      "activityDateTime": "2021-01-30T14:11:02Z",
      "outcome": "success",
      "performer": {
        "displayName": "Adam Admin",
        "id": "V0ZWc2VyHzE0NT8xNzAyMDA",
        "ipAddress": "192.168.1.1",
        "type": "com.workiva.iam.principal.user",
        "uniqueName": "admin_admin@example.com"
      },
      "summary": "Adam Admin added the user 'John Public' to the workspace 'Organization Management'",
      "targets": [
        {
          "displayName": "John Public",
          "id": "V0ZVc2VyHzY0ODY4NjQ1MzE1NTQ",
          "type": "com.workiva.administration.user",
          "uniqueName": "john_public"
        },
        {
          "displayName": "Organization Management",
          "id": "QWNjb3VudB81MzIzMjkwOTM4NzAzODcy",
          "type": "com.workiva.administration.workspace"
        }
      ],
      "organization": {
        "id": "a25bc16f-fb62-4aff-a87e-1cca4b2113c0",
        "name": "Workiva"
      },
      "workspace": {
        "id": "QWNjb3VudB81MzIzMjkwOTM4NzAzODcy",
        "name": "Organization Management"
      },
      "tags": [
        "correlationId:1a2b3c4d5e6f000db88c0009f9f1",
        "eventId:LM4s-wJyTgW4NTbNZi_86v"
      ]
    }
  ]
}

Key response fields:

  • data — An array of Activity objects.

  • @nextLink — A URL to retrieve the next page of results. If absent, you have reached the last page.

  • action.alias — The recommended human-readable identifier for the type of action. Use this field (not action.id) to categorize activities in your integration.

  • performer — Who performed the action, including their IP address.

  • targets — The resources affected by the action. An activity can affect multiple targets (e.g., a user and a workspace).

  • summary — A human-readable description of what happened.

  • attachments — When present, provides additional context such as old/new values for a changed property.

Pagination#

Results are paginated. To retrieve all activities, follow the @nextLink URL until it is no longer present in the response. Use $maxpagesize to control how many results are returned per page.

curl -X GET "https://api.app.wdesk.com/organizations/${ORG_ID}/activities?\$maxpagesize=100" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01"

Tip: When paginating through a large set of activities, persist the @nextLink URL between iterations. It is an opaque cursor that internally encodes a $next query parameter — do not attempt to construct or modify it manually. Always use the full @nextLink URL as-is for the next request.

Sorting#

Activities are typically returned in descending order by activityDateTime (newest first), but the API does not guarantee a default sort order. Always set $orderBy explicitly to ensure predictable results:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$orderBy=activityDateTime asc'

Tip: Use asc ordering when building incremental exports so that you process activities in chronological order and can reliably track the last-processed timestamp.


Retrieving Activities for a Specific Workspace#

To retrieve activities scoped to a single workspace, include the workspaceId in the path. The response format is identical to the organization-level endpoint.

Required scope: activity:read

GET /organizations/{organizationId}/workspaces/{workspaceId}/activities

curl -X GET "https://api.app.wdesk.com/organizations/${ORG_ID}/workspaces/${WORKSPACE_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01"

Response (200 OK):

{
  "@nextLink": "<opaque_url>",
  "data": [
    {
      "id": "NjE0MjIxODIt...",
      "action": {
        "alias": "workspace_update",
        "category": "Administration",
        "deprecated": false,
        "id": "com.workiva.administration.workspace.update",
        "name": "Workspace updated"
      },
      "activityDateTime": "2021-01-30T13:55:01Z",
      "outcome": "success",
      "performer": {
        "displayName": "Adam Admin",
        "id": "V0ZWc2VyHzE0NT8xNzAyMDA",
        "ipAddress": "192.168.1.1",
        "type": "com.workiva.iam.principal.user",
        "uniqueName": "admin_admin@example.com"
      },
      "summary": "Adam Admin updated the workspace 'Organization Management'",
      "attachments": [
        {
          "entityChanges": {
            "new": "Organization Management",
            "old": "New Workspace",
            "propertyName": "displayName"
          }
        }
      ],
      "targets": [
        {
          "displayName": "Organization Management",
          "id": "QWNjb3VudB81MzIzMjkwOTM4NzAzODcy",
          "type": "com.workiva.administration.workspace"
        }
      ],
      "organization": {
        "id": "a25bc16f-fb62-4aff-a87e-1cca4b2113c0",
        "name": "Workiva"
      },
      "workspace": {
        "id": "QWNjb3VudB81MzIzMjkwOTM4NzAzODcy",
        "name": "Organization Management"
      },
      "tags": [
        "correlationId:2a1b4dee6e9f001dbbbc0007f7f3",
        "eventId:k94s-vJyTaca5HERbNZi_21v"
      ]
    }
  ]
}

Note: The attachments array, when present, provides before/after values for changed properties. In the example above, the workspace displayName was changed from “New Workspace” to “Organization Management”. Not all activities include attachments. Attachments are generic JSON elements whose structure varies by action type — for example, a property change may use entityChanges with propertyName, old, and new fields, while a toggle may use a simpler {enabled: {new: true, old: false}} structure. Always inspect attachments defensively in your integration.

The same pagination, sorting, and filtering options available on the organization-level endpoint apply here.


Filtering Activities#

Both the organization and workspace activities endpoints support the $filter query parameter. Filtering is essential for building targeted reports — for example, retrieving only login activities for the last 30 days, or finding all actions performed by a specific user.

Available Filter Fields#

Field

Supported Predicates

Description

action.alias

eq, in

Filter by activity action type (e.g., user_login)

action.id

eq, in

Filter by the fully qualified action identifier

activityDateTime

eq, lt, gt, le, ge

Filter by when the activity occurred

performer.id

eq, in

Filter by who performed the action

target.id

eq, in

Filter by which resource was affected

Logical operators and and or can be used to combine filter expressions.

Note: Only the fields listed above support server-side filtering. Other activity fields — including outcome, summary, tags, and performer.uniqueName — are not filterable via $filter. To filter on these fields, retrieve the activities first and apply the filter in your application logic.

Example: Activities in a Date Range#

Retrieve all activities that occurred in January 2026:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=activityDateTime ge 2026-01-01T00:00:00Z and activityDateTime lt 2026-02-01T00:00:00Z'

Example: Activities by a Specific User#

Retrieve all activities performed by a specific user, identified by their performer ID:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=performer.id eq "V0ZWc2VyHzE0NT8xNzAyMDA"'

Example: Only Login Activities#

Retrieve only user login activities using the action.alias filter:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=action.alias eq "user_login"'

Example: Activities Targeting a Specific User#

To find all activities that affected a particular user (e.g., when their role was changed, when they were added to a workspace), filter by target.id:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=target.id eq "V0ZVc2VyHzY0ODY4NjQ1MzE1NTQ"'

Tip: Filtering by target.id is the way to answer the question “what has happened to this user?” as opposed to “what has this user done?” (which uses performer.id).

Example: Combining Filters#

Retrieve all login activities for a specific user in the last 7 days:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=performer.id eq "V0ZWc2VyHzE0NT8xNzAyMDA" and action.alias eq "user_login" and activityDateTime ge 2026-01-24T00:00:00Z'

Note: The outcome field is not available as a server-side filter. This query returns both successful and failed logins. To isolate failures, filter the results by outcome in your application logic after retrieval.

Example: Multiple Action Types#

Use the in predicate to retrieve activities matching any of several action types:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=action.alias in ("user_login", "workspace_membership_create", "workspace_membership_delete")'

Discovering Available Activity Actions#

Before building filters, you need to know which action types exist. The GET /activityActions endpoint returns the full catalog of actions that may produce activities.

Required scope: activity:read

GET /activityActions

curl -X GET "https://api.app.wdesk.com/activityActions" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01"

Response (200 OK):

{
  "@nextLink": "<opaque_url>",
  "data": [
    {
      "alias": "workspace_membership_create",
      "category": "Administration",
      "deprecated": false,
      "id": "com.workiva.administration.workspace_membership.create",
      "name": "Workspace membership created"
    },
    {
      "alias": "workspace_membership_delete",
      "category": "Administration",
      "deprecated": false,
      "id": "com.workiva.administration.workspace_membership.delete",
      "name": "Workspace membership deleted"
    }
  ]
}

Key fields:

  • alias — The recommended human-readable identifier for the action type. Use this in $filter expressions (e.g., action.alias eq "workspace_membership_create").

  • name — A descriptive label for the action type.

  • category — Groups actions into categories (e.g., “Administration”).

  • deprecated — If true, this action type has been identified for removal in a future release. Avoid building new integrations against deprecated actions.

Warning: The Workiva Platform does not guarantee that actions taken in the platform will always result in the same Activity ID. Use the alias field to classify activities — do not rely on an activity’s id for categorization or deduplication.

Sorting Activity Actions#

You can sort the results by id or name:

curl -G "https://api.app.wdesk.com/activityActions" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$orderBy=name asc'

Tip: Call GET /activityActions once and cache the results in your application. The catalog of actions changes infrequently, and caching avoids unnecessary API calls. Refresh periodically (e.g., weekly) to pick up new action types.


Retrieving a Single Activity by ID#

If you have a specific activity ID (e.g., from a previous list response or a stored reference), you can retrieve its full details directly.

Required scope: activity:read

GET /activities/{activityId}

curl -X GET "https://api.app.wdesk.com/activities/${ACTIVITY_ID}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01"

Response (200 OK):

{
  "id": "NjE0MjIxODIt...",
  "action": {
    "alias": "workspace_membership_create",
    "category": "Administration",
    "deprecated": false,
    "id": "com.workiva.administration.workspace_membership.create",
    "name": "Workspace membership created",
    "type": "com.workiva.administration.workspace_membership.create"
  },
  "activityDateTime": "2021-01-30T13:55:01Z",
  "outcome": "success",
  "performer": {
    "displayName": "Adam Admin",
    "id": "V0ZWc2VyHzE0NT8xNzAyMDA",
    "ipAddress": "192.168.1.1",
    "type": "com.workiva.iam.principal.user",
    "uniqueName": "admin_admin@example.com"
  },
  "summary": "Adam Admin added the user 'John Public' to the workspace 'Organization Management'",
  "targets": [
    {
      "displayName": "John Public",
      "id": "V0ZVc2VyHzY0ODY4NjQ1MzE1NTQ",
      "type": "com.workiva.administration.user",
      "uniqueName": "john_public"
    }
  ],
  "organization": {
    "id": "d6e178fd-4dd5-47e5-9457-68dd64b03655",
    "name": "Workiva Inc."
  },
  "workspace": {
    "id": "QWNjb3VudB81NjM5NDQ1NjA0NzI4ODMy",
    "name": "Organization Management"
  },
  "tags": [
    "correlationId:1a2b3c4d5e6f000db88c0009f9f1",
    "eventId:LM4s-wJyTgW4NTbNZi_86v"
  ]
}

Note: The Activity schema defines summary for the human-readable description of what happened. Some API reference examples show this field as description. Your integration should handle both field names defensively.

Warning: Activity IDs are not guaranteed to be stable. The same action taken in the platform may produce different activity IDs over time. Always use action.alias to determine whether an activity is relevant to your use case — never rely on the activity id for classification.


Building a Recurring Activity Export#

A common use case is to run a scheduled job that pulls new activities and forwards them to an external system — a SIEM (e.g., Splunk, SumoLogic), a data warehouse, a compliance tool, or a CSV file for auditors. This section walks through the recommended pattern.

The Incremental Pull Pattern#

The core idea is to track the timestamp of the last activity you successfully processed, then use $filter on subsequent polls to retrieve only activities that occurred after that timestamp.

Step 1 — Initial Pull#

On the first run, retrieve activities for your desired lookback window. For example, the last 30 days:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=activityDateTime ge 2026-01-01T00:00:00Z' \
  --data-urlencode '$orderBy=activityDateTime asc' \
  --data-urlencode '$maxpagesize=200'

Process all pages by following the @nextLink URL until it no longer appears. Record the activityDateTime of the last activity you processed.

Step 2 — Subsequent Pulls#

On each subsequent run, use the stored timestamp to retrieve only new activities:

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=activityDateTime gt 2026-01-15T14:11:02Z' \
  --data-urlencode '$orderBy=activityDateTime asc' \
  --data-urlencode '$maxpagesize=200'

Replace 2026-01-15T14:11:02Z with the activityDateTime from the last activity you processed. Using gt (greater than) avoids re-processing the same activity.

Important: Use $orderBy=activityDateTime asc for incremental pulls. This ensures you process activities in chronological order. If your job is interrupted mid-pagination, you can resume from the last processed timestamp without missing records.

Step 3 — Handle Pagination#

Continue following @nextLink until there are no more pages:

curl -X GET "<@nextLink_url>" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01"

After processing each page, update your stored timestamp to reflect the latest activityDateTime in that page.

Narrowing the Export#

Combine the timestamp filter with action type filters to export only the activities you care about. For example, to export only security-relevant activities (logins and workspace membership changes):

curl -G "https://api.app.wdesk.com/organizations/${ORG_ID}/activities" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/json" \
  -H "X-Version: 2026-01-01" \
  --data-urlencode '$filter=activityDateTime gt 2026-01-15T00:00:00Z and action.alias in ("user_login", "workspace_membership_create", "workspace_membership_delete", "workspace_update")' \
  --data-urlencode '$orderBy=activityDateTime asc' \
  --data-urlencode '$maxpagesize=200'

Tip: Use GET /activityActions to discover the full list of available action aliases, then select the ones relevant to your compliance or security requirements. Action aliases not present in the catalog will silently return zero results, so always verify aliases before using them in filters.


Common Issues#

Issue

Solution

“I expected Workiva to push events to my SIEM/IdP/SFTP”

The Activities API is pull-only. You must poll the API on a schedule and forward the data to your external system. There are no webhooks or push mechanisms.

“Activity names are vague — I don’t know what they mean”

Call GET /activityActions to retrieve the full catalog of action types with their alias, name, and category. Use alias values in your filter expressions.

“I’m seeing duplicate activities across polls”

Use $filter=activityDateTime gt <last_timestamp> (strict greater-than) rather than ge to avoid reprocessing the boundary record.

“Activity IDs changed for the same type of action”

Activity IDs are not stable. Classify activities using action.alias, not by their id.

“I want cell-level change tracking”

The Activities API records administrative and platform-level actions (logins, role changes, workspace settings). It does not provide cell-level or content-level change history. Use the cell history feature in the Workiva UI for that.

“I can’t access activities — getting 403 Forbidden”

The authenticated user must hold an admin role (Org User Admin, Org Workspace Admin, Org Security Admin, or Workspace Owner). Verify the user’s roles and ensure the OAuth 2.0 token includes the activity:read scope.

“Timestamps are in UTC — I need local time”

The API returns all timestamps in UTC (activityDateTime uses ISO 8601 format). Convert to your local timezone in your application logic.

“I see deprecated actions in the list”

Actions with deprecated: true are scheduled for removal. Avoid building new integrations against them. Check GET /activityActions periodically for changes.

“I need to filter by who was affected, not who performed the action”

Use $filter=target.id eq "<userId>" to find activities where a specific user was the target of an action (e.g., their role was changed or they were added to a workspace).

Error Responses#

All activities endpoints return standard error responses. The most common error codes are:

Status

Code

Meaning

401

401Unauthorized

The OAuth 2.0 token is missing, expired, or invalid.

403

403Forbidden

The authenticated user lacks the required admin role or the token is missing the activity:read scope.

404

404NotFound

The organization or workspace ID does not exist.

429

429TooManyRequests

You have exceeded the API rate limit. Back off and retry after the period indicated in the response.

Error responses follow this shape:

{
  "code": "403Forbidden",
  "message": "The API token does not have permissions to perform the request"
}

Summary of API Endpoints#

Operation

Method

Endpoint

Required Scope

List organization activities

GET

/organizations/{organizationId}/activities

activity:read

List workspace activities

GET

/organizations/{organizationId}/workspaces/{workspaceId}/activities

activity:read

Get single activity

GET

/activities/{activityId}

activity:read

List activity actions

GET

/activityActions

activity:read