API Reference

Graph Guide

Introduction to Graph Endpoints

The Graph endpoints enable access to Integrated Risk workspaces, such as to pull reports and records, create and edit records, and more. This documentation provides a few example workflows for common use cases. To access the Graph endpoints, first set up proper authorization in your workspace and retrieve a token. Next, verify the API user has permission to the desired data elements and reports. This can be accomplished by granting this user the Data Admin role.

To access the Graph endpoints, first set up proper authorization in your workspace and retrieve a token.

Pull Data Out of the Workiva Platform

Data retrieval from the Workiva Platform is common, such as to:

  • Push SOX or Audit data to a governance, risk management, and compliance (GRC) tool
  • Back up data in a repository
  • Push information into an analytics or dashboarding tool

To pull most graph data out of the Workiva platform, you can use the Graph Reports endpoint. This endpoint enables you to retrieve CSV files of reports in your workspace, customized to best meet your needs. If data is important enough to retrieve via API, it likely already exists as a report. If not, you can work with Customer Support to write new reports or augment existing ones.

Reports are referenced via a permanent reportId. There are multiple ways to determine a report's reportId, but the simplest is to browse to the report and copy the ID from its URL.

With the reportId, you can retrieve the CSV with this curl command:

curl -H "Authorization: Bearer ${token}" https://api.app.wdesk.com/platform/v1/graph/reports/<reportId>/csv

Create New Records

The Graph endpoints are commonly used to add new records, such as Controls and Issues. Establishing a workflow to create records via the Graph endpoints requires some initial effort and potential back-and-forth with Support, but it should be trivial to then repeat the same pattern.

At a high level, establishing the workflow follows this process:

  1. Verify the Workiva Platform data model is set up to receive the data of interest.
  2. Determine the names of the data model elements—the properties and relationships—used in the API import.
  3. Determine the recordId of relationship targets.
  4. Programatically build a json file to define the data to import.

In the graph database, each record has a unique and static record ID, encoded as a universally unique identifier (UUID). For many records, a human-readable "ID" is available, such as "Issue 001". While the human-readable ID may not be unique, the underlying UUID is.

This example assumes working with Issues, but the principles extend to any class of record.

Verify the Workiva Platform Data Model

Based on discovery during onboarding, each user account likely features customized data models for Issues. Fortunately, the graph database features a robust and customizable data model to meet your specific needs. Since your source system for Issues may have a different data model than the Workiva Platform, it's important to first perform a field-to-field mapping.

To ensure all necessary fields exist, create a single Issue in the Workiva Platform through the UI. If any necessary fields are missing from the Workiva Platform, work with Support to add them to your account's data model.

Determine the Names of the Data Model Elements

After you successfully create a record in the Workiva Platform to establish the mapping, determine the underlying data structure elements. The Graph endpoints provide a way to return the underlying data model. In addition to properties, relationships can be requested.

curl -G -H "Authorization: Bearer ${token}" "https://api.app.wdesk.com/platform/v1/graph/types/Issue" --data-urlencode '$expand=relationships'

To present the underlying data model's fields, the Workiva Platform UI uses human-readable labels, which can be configured per account. While most fields should be intuitive, you can reach out to Workiva Support to verify how UI labels translate to the underlying data model; however, the Types endpoint should help point you in the right direction.

Determine Record IDs for Relationship Targets

In a Graph database, interesting data includes relationships—or edges—from one record to another. For example, an Issue may have a relationship to its deficient Control, the Person who found the issue, or its Severity level. If you create an Issue with a relationship to another record, the record ID of the target is necessary to set the edge between the two.

Data from a third-party system likely references relationship targets with human-readable data fields rather than the underlying Workiva Platform UUID record ID. Thus, it may be useful to first query for all potential target records. For example, to create an Issue that has a relationship to a Control, you'll need the Control's record ID. To locate the record ID, do one of the following:

  • Maintain a lookup table of Controls and their corresponding Workiva Platform record IDs.
  • Craft a report to pull record IDs as a CSV as needed.
  • Perform a query for all Control records and use the returned json as the lookup table.
curl -G -H "Authorization: Bearer ${token}" "https://api.app.wdesk.com/platform/v1/graph/records" --data-urlencode '$filter=type eq Control'

You can make similar requests for Person records, Issue Severity records, and any other relationship target.

Programatically Build the Edits Object

Database edits, including creates, are expressed in a json format. For formal documentation, consult the edit endpoint documentation.

To create a new record, you'll need its type, such as Control, Issue, etc.

Optionally, a temporaryRecordId may be provided in create_record blocks and used in subsequent create_relationship blocks for the same set of edits. A mapping between temporaryRecordId and the real recordId is provided on the response.

For a new record to be useful, you should define at least a few properties and any edges to other records:

  • Properties are set during the record's creation.
  • Edges are set after the record's creation.

To create records, you'll likely receive a tabular list of records to create, with each row representing a new record. The graph Edit endpoint requires this information as a json object that contains:

  • A create_record block with the type and properties of the record to create.
  • A create_relationship block for each edge to set between records.

For example, this json shows a new Issue record—as set by type–with three user-facing properties and one relationship. The targetID085ce4f5-8687-4cb0-aad6-d5c4e1a89a3d—represents a Control record in the account:

[
    {
        "operation": "create_record",
        "temporaryRecordId": "<user-generated-temporary-id-for-this-issue-record>",
        "type": "Issue",
        "properties": {
            "id": {
                "datatype": "string",
                "value": "User ID for the issue"
            },
            "secondProperty": {
                "datatype": "string",
                "value": "This is a second property"
            }
        }
    },
    {
        "operation": "create_relationship",
        "label": "indicates_issue_on_control",
        "recordId": "<user-generated-temporary-id-for-this-issue-record>",
        "targetId": "085ce4f5-8687-4cb0-aad6-d5c4e1a89a3d"
    }
]

To create your json object, use your preferred programming language. For example, a simple Python program to generate a json object like the one above:

import json
import requests
import sys

# Using the already known Control recordId
control_record_id = "085ce4f5-8687-4cb0-aad6-d5c4e1a89a3d"

# Create edit json for creating a new record with a temporaryRecordId
record_temp_id = "issue1"
create_record = {
    "operation": "create_record",
    "temporaryRecordId": record_temp_id,
    "type": "Issue",
    "properties": {
        "id": {
            "datatype": "string",
            "value": "User ID for the issue"
        },
        "secondProperty": {
            "datatype": "string",
            "value": "This is a second property"
        }
    }
}

# Create edit json for creating a relationship between new record and
# the existing Control
create_relationship = {
    "operation": "create_relationship",
    "label": "indicated_issue_on_control",
    "recordId": record_temp_id,
    "targetId": control_record_id
}

# Create list of all edits to apply
edits = [create_record, create_relationship]

# Save object to .json file for use with edits endpoint
with open("edits.json", "w+") as f:
    json.dump(edits, f)



# Optionally, perform edits request with json from python
access_token = "<token retrieve with https://api.app.wdesk.com/iam/v1/oauth2/token endpoint>"
headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': f'Bearer {access_token}'
}

r = requests.post('https://api.app.wdesk.com/platform/v1/graph/edits', json=edits, headers=headers)

if r.status_code != 201:
    print(f'Failed edits request. Code: {r.status_code} Response: {r.json()}')
    sys.exit(1)

# Check record and relationship was created using recordIdMap returned from post to
# edits to map the new record's temporaryRecordId to recordId
new_issue_record_id = r.json()["recordIdMap"][record_temp_id]

r = requests.get(f'https://api.app.wdesk.com/platform/v1/graph/records/{new_issue_record_id}?$expand=relationships', headers=headers)

if r.status_code != 200:
    print(f'Failed to retrieve record. Code: {r.status_code}  Response: {r.json()}')
    sys.exit(1)

print(json.dumps(r.json(), indent=2))

Edit Existing Records

Editing records follows a similar pattern as creating new ones. The biggest difference is that when you add relationships to an existing record, consider how to handle existing relationships of that same class:

  • Some classes of relationships require multiple targets. For example, a single Issue record may indicate an issue in multiple Controls.
  • Other classes of relationships require only a single target. For example, a relationship to an Issue Severity likely has only a single target; it doesn't make sense to identify a single issue as both a Material Weakness and Deficiency.

The Graph Edit endpoint enables the addition and removal of relationships between records; it's up to you to remove any existing relationships as needed.

To edit a record, find the record and submit its edits, including the removal of any relationships. Finding the record requires its recordId and, optionally, its current properties and relationships. If the record is kept in sync between the Workiva Platform and another system, you may wish to store the Graph recordId in the other system or another location to facilitate lookup. Otherwise, you can use the Graph endpoints to pull records of various types as previously described.

Here, we add parameters to include relationships in the results:

curl -G -H "Authorization: Bearer ${token}" "https://api.app.wdesk.com/platform/v1/graph/records" --data-urlencode '$filter=type eq Issue' --data-urlencode '$expand=relationships'

By including relationships, you can indicate whether to remove any relationships as part of the edit. To determine relationships between records, include a relationship block. For example, this snippet indicates an Issue record—033a531f-c741-4a97-bc09-bb72358e75ad–with a severity_of_issue
relationship to a record with recordId 008c4041-e941-4478-88ea-8ae74b21f6bf:

    {
        "displayLabel": "Severity of Issue",
        "label": "severity_of_issue",
        "fromType": "Issue",
        "toType": "Issue Severity",
        "fromRecord": "033a531f-c741-4a97-bc09-bb72358e75ad",
        "toRecord": "008c4041-e941-4478-88ea-8ae74b21f6bf"
    }

To remove the relationship to the Issue Severity, set a new relationship, and change the summary property:

[
    {
        "operation": "delete_relationship",
        "label": "severity_of_issue",
        "recordId": "033a531f-c741-4a97-bc09-bb72358e75ad",
        "targetId": "008c4041-e941-4478-88ea-8ae74b21f6bf"
    },
    {
        "operation": "create_relationship",
        "label": "severity_of_issue",
        "recordId": "033a531f-c741-4a97-bc09-bb72358e75ad",
        "targetId": "9569e1a5-d537-4bf8-874e-0b959cd2d3b3"
    },
    {
        "operation": "set_properties",
        "recordId": "033a531f-c741-4a97-bc09-bb72358e75ad",
        "properties": {
            "summary": {
                "value": "My updated Issue Summary",
                "datatype": "string"
            }
        }
    }
]