Priority Matrix Developer Guide

Note: This is a live, interactive document, and some features are only available for logged in users. Sign in now to get a more complete experience.

What is this document?

Here you will learn the basic details of the Priority Matrix API, getting ready to interact with the system programmatically. With the information provided in this document, you will be able to:

  • Understand the elements in the Priority Matrix data model
  • Create an application that connects to Priority Matrix on behalf of a user
  • Access Priority Matrix data associated with a user
  • Make changes to Priority Matrix data

We update this document periodically. If you find a mistake, please let us know. For any questions regarding this documentation, the API, or Priority Matrix in general, please contact us and we'll get back to you as soon as possible. Especially if you would like to see a concrete example or explanation, don't hesitate to send us a message and let us know how we can assist.

Principal entities

While the Priority Matrix data model is quite extensive, most applications need only to deal with a handful of entities. Here is a brief outline, including links to explore:

  • User: This element represents a person using Priority Matrix. User objects contain basic identifying information such as their email address, first and last name, time of creation, etc.
  • UserProfile: Every user has an associated profile object with extensive information beyond what's in the User object. For example, an avatar image URL, notification preferences, local time zone, some subscription information, a list of collaborators, and so on. Users can edit some of these details in the user preferences page.
  • Me: A special User-like object can be queried to retrieve plenty of information about the current user. This entry bundles basic data from the User and UserProfile entities, and extends it with additional details such as calendar subscription URLs, subscription levels, and more.
  • Account: Organizations are represented by their Priority Matrix Account object. An account is uniquely identified by an email address, which is typically the email of the account member who first registered in the system. An account has a single user deemed as the admin(administrator), with capacity to add or remove members from the account. You can view details about your organization in your account management page. The list of current account members can be retrieved via the special path /api/v1/account/users.
  • Item: An item is the unit of work in our system. It can represent a task, an idea or a note that a user captures for future reference. Items have several fields, ranging from the basic ones (name, descriptionText, startDate, dueDate, owner, followers) to the more esoteric:
    • quadrant: ranging from 0 to 3, indicates the position of the item in the 2x2 matrix (0 is top-left, 1 is top-right, 2 is bottom-left, 3 is bottom-right). Note that in our app's interface we shift the range to 1-4 in user facing views, so Q1 corresponds to quadrant=0, and so on.
    • state: An item can be in a Normal state (0), Completed (1), Trashed (2) or Deleted (3). The difference between Trashed(2) and Deleted(3) is subtle and not too relevant for applications: A Trashed item can be restored using the client apps, whereas a Deleted item has been removed from all client apps, and is slated for removal from our database.
  • Project: A project represents a collection of items, organized in a 2x2 matrix (hence the name of our application). Note that the unique identifier for a project is given in field idd (instead of id), for historical reasons. The collection of items for a project can be retrieved via /project/{idd}/items. A project can have one or more owner users, who have access to the project and its contents.

Authentication

We use OAuth 2.0 for authentication, as documented in https://oauth.net/2/. There are several libraries and tools that can interact with our authentication system. The easiest way to work with the API is to obtain an authentication token which identifies you as a user in Priority Matrix. There are multiple ways to do this.

Via standalone token

The fastest way to start working is to generate a standalone token for your Priority Matrix account. This token uniquely identifies your user in the system, and it has an optional expiration date. In the following link you can see your authorized tokens list, as well as create new ones. Once you have this token, you can use it as your bearer token authorization header in all API requests.

Via registered app token

A more traditional approach to operating with OAuth2 is to register an application, which in turn provides you with an authentication token. Later you will exchange this authentication token for an access token, which is what you use in your API requests.

Registering an application

You only need to follow these steps once, to register an application which gives you a client ID and client secret (equivalent to a login and password).

  1. Go to https://sync.appfluence.com/o/applications/
  2. Create a new application with the following values for a typical setup:
    • name: any unique name
    • client type: confidential
    • authorization grant type: "Resource owner password-based"
  3. Before submitting, securely store the client ID and client secret, and treat these values like they are passwords. This is the last time you'll be able to see your client secret, as it's stored in non-reversible hashed form. If you lose it, you'll need to register a new application.

Obtaining an access token

Once you have your client ID and client secret from the step above, you can exchange them for an access token as explained below:

  • Send a POST to https://sync.appfluence.com/o/token/ with the following values:
    • grant_type: password
    • client_id: [your client ID from above]
    • client_secret: [your client secret from the creation step above]
    • username: [your PM username]
    • password: [your PM password]
    Note that the username and password are your Priority Matrix credentials, and that the client secret is the one you obtained when creating the application. If you try to use the value shown in the application details, it won't work because that's the hashed version.
  • In the response, get the value in the 'access_token' field.
  • Use that access_token as a bearer token authorization header in all API requests.
  • Your access token is valid for about a year. To refresh it, POST to https://sync.appfluence.com/o/token/ with the following values:
    • grant_type: refresh_token
    • client_id: [your client ID from above]
    • client_secret: [your client secret from the creation step above]
    • refresh_token: [your refresh_token from the initial response above]

Common API calls

Here is a brief list of API queries for common operations. More will be added over time. If you're interested in a particular operation and can't figure out the details, please let us know. Note that for the sake of conciseness, we're omitting the prefix https://sync.appfluence.com which should precede each of the following partial URLs.

Users and collaborators

  • Details of current user
    GET /api/v1/me/
  • Collaborators known by current user
    GET /api/v1/me/collaborators/
  • Users known by the current user
    GET /api/v1/user/
  • Details for user with ID 123
    GET /api/v1/user/123/
  • Details on current account
    GET /api/v1/account/
  • Members of current account
    GET /api/v1/account/users/

Projects

  • Active projects (state 0) for current user
    GET /api/v1/project/?state=0
  • Details for project with IDD 234
    GET /api/v1/project/234/
  • Create a project
    POST /api/v1/project/
  • Items for a project
    GET /api/v1/project/234/items/
  • Completed items (state=1) for a project
    GET /api/v1/project/234/items/?state=1
  • Items in the bottom-right quadrant of project with IDD 234
    GET /api/v1/project/234/items/?quadrant=3
  • Summarized data for items in a project (faster than full item data)
    GET /api/v1/project/234/item_summaries/
  • List of owners of a project
    GET /api/v1/project/234/owners/
  • Tags for a project
    GET /api/v1/project/234/tags
  • List of projects tagged "abc"
    GET /api/v1/project/?tag__name=abc

Items

  • All items known to the current user
    GET /api/v1/item/
  • Details for item with ID 345
    GET /api/v1/item/345/
  • Users that follow an item
    GET /api/v1/item/345/followers
  • Tags for an item
    GET /api/v1/item/345/tags
  • Comments for an item
    GET /api/v1/item/345/comments
  • items in inbox
    GET /api/v1/me/inbox/
  • Create item
    POST /api/v1/item/
  • Create tag (for a project or item)
    POST /api/v1/tag/ (more details below)
  • List of items tagged "abc"
    GET /api/v1/item/?tag__name=abc

Concrete examples

Example 1: Get the project for an item

Assuming we have an item with ID 345 and we want to know something about the project that contains it. The following steps describe this process:

  1. GET the item via /api/v1/item/345/
  2. Inspect the output and get the value of the projects field, something like:
    ["/api/v1/project/234"]
    Note that if the project is inbox, it won't have a project, and this field will be blank.
  3. GET the project details via /api/v1/project/234

Example 2: Create an item in an existing project

Given a preexisting project with IDD 234, you can create a new item in that project by POSTing a message to /api/v1/item/ with a body like the JSON below (you can include more values if you prefer, but these are the recommended minimum):

{
    "name": "The item name",
    "descriptionText": "The item notes, in plain text.",
    "owner": "your@email.com",
    "projects": [
        "/api/v1/project/234/"
    ]
    "quadrant": 0
}

Note: if "projects" field is empty item will be saved in your inbox.

Example 2.1: Edit notes in an item

If you want to edit the notes of an item with ID 345, you can do so by sending a PUT message to /api/v1/item/345/ with the following JSON:

{
    "descriptionText": "The new notes for the item."
}

Note that you can do the same for other fields, such as name, quadrant, etc.

Example 3: Adding a comment to an item

The resource path for item comments is /api/v1/comment/. In order to create a comment on an item with ID 345, you can send a POST message with the following JSON:
{
    "text": "The comment text",
    "item": "/api/v1/item/345/"
}

The user that's currently authenticated will be the author of the comment.

Example 4: Adding and deleting tags

The mechanism for dealing with tags is analogous for both items and projects. In general, you work by POSTing a message to /api/v1/tag/ with 3 key values:

  • object: This can be either a project or item URL, such as /api/v1/project/234/ or /api/v1/item/345/, and it indicates the type of tag you want to use.
  • name: This is the actual name (or label) for the tag. It's context dependent
  • action: This can be 'add' or 'remove', which is pretty self-explanatory.

Let's see some specific examples.

Adding a tag to an existing item

In order to add the tag "abc" to an item with ID 345, send the following JSON in a POST message to /api/v1/tag/:

{
    "name": "abc",
    "action": "add",
    "object": "/api/v1/item/345/"
}

Deleting a preexisting project tag

In order to remove the tag "xyz" from a project with IDD 234, send the following JSON in a POST message to /api/v1/tag/:

{
    "name": "xyz",
    "action": "remove",
    "object": "/api/v1/project/234/"
}

Example 5: Filtering by date

Most dates in our system are encoded in seconds since 1970, what is known as Unix or epoch date. Several online services can be used to quickly convert date formats, such as epochconverter.comand others. Most programming languages include tools to do this conversion as well.

In general, filtering by date is done via URL parameters with the following format:

  • A date selector, such as dueDate, startDate, creationDate, completionDate, timestamp
  • A comparator, joined with double underscore (__), like le (less-than), lte (less-than or equal), ge (greater-than), gte (greater-than or equal)
  • The given date limit, typically as an integer, in epoch format

Let's see some examples below, in some cases combining with other query types.

  • Items with due date previous to 02/17/2017
    /api/v1/item/?creationDate__gt=1487328456
  • Items with dueDate after 02/17/2017 and startDate earlier than 02/11/2017
    /api/v1/item/?startDate__gt=1487328456&startDate__gt=1487328456
  • Active projects created after 2/17/2017
    /api/v1/project/?state=0&creationDate__gt=1487328456
  • Deleted projects created earlier than 2/17/2017
    /api/v1/project/?state__gt=0&creationDate__lt=1487328456
  • Projects starting after 2/17/2017
    /api/v1/project/?startDate__gt=1487328456
  • Projects finishing earlier than 2/17/2017
    /api/v1/project/?endDate__lt=1487328456

Note: When querying by timestamp, it is often wise to use both lt/lte and gt/gte parameters to bound the time query at both ends. Otherwise, if we only use gt/gte and the query returns multiple pages, it is possible that subsequent pages return results inconsistent with the previous ones (because the timestamps change in between the queries for each page).

Pagination

Most API resources in Priority Matrix support pagination to help manage large result sets efficiently. There are two ways to navigate through paginated results:

Using limit and offset

You can control pagination by adding URL parameters:

  • limit: Controls how many items are returned per page (default varies by endpoint)
  • offset: Indicates how many items to skip before starting to return results

For example, to get the second page of items with 30 items per page:

/api/v1/item/?limit=30&offset=30

Using the next field

Each paginated response includes metadata that helps with navigation:

  • meta.next: URL for the next page of results (null if you're on the last page)
  • meta.previous: URL for the previous page (null if you're on the first page)
  • meta.total_count: Total number of items available
  • meta.limit: Current page size
  • meta.offset: Current offset

For example, a query to /api/v1/item/?limit=30 might return metadata like:

{
    "meta": {
        "limit": 30,
        "next": "/api/v1/item/?limit=30&offset=30",
        "offset": 0,
        "previous": null,
        "total_count": 85
    },
    "objects": [...]
}

Using the next URL is the recommended way to navigate through pages, as it ensures you're using the correct parameters and maintains any additional query filters you've applied.

Complete Projects

People have developed various apps using the Priority Matrix app. Some are complete, functional integrations. Some others are more like toy projects, developed just to solidify learnings. Below are some examples. If you have your own project and would like us to list it here, let us know.

  • LazyToday is a command-line tool written in Node.js that shows you your pending PM items, and lets you postpone them to a future date.
  • GordonGekko is a Python app that checks the daily changes in a given stock market ticker value, and creates new PM items recommending whether to buy or sell that stock.
  • pmrustcli is a very complete tool written in Rust to interact with the API using the command line.

Webhooks

Priority Matrix supports a basic webhook model, which lets connected apps be notified of changes to a user's own Priority Matrix data. This facilitates automatic syncing across applications, and it's at the core of systems like Microsoft Power Automate and similar.

Suported webhook events (or triggers)

The following is a list of currently supported events triggered by Priority Matrix. A webhook can be configured to listen to each one of them, delivering notifications to 3rd party URLs in order to process them.

  • project.created
    Payload will be the JSON representation for the created project.
  • item.created
    Payload will be the JSON representation for the created item.
  • item.quadrant.updated
    The payload will be the following JSON representation of the modified item:
    • id: item id
    • name: item name
    • quadrant: new quadrant
    • old_quadrant: the previous quadrant
    • project_id: project id (a.k.a. project IDD in this document)
    • project_name: the project name
    • item.completed
  • item.deleted
    Payload will be the JSON representation for the modified item.

Payload details

This is an example of a "item.quadrant.updated" hook that may have been triggered:

{
  "hook": {
    "account": "/api/v1/account/12/",
    "target": "https://somewebsite.com/receive_hooks/",
    "triggered_by": "/api/v1/user/123/",
    "enabled": true,
    "user": "/api/v1/user/123/",
    "event": "item.quadrant.updated",
    "resource_uri": "/api/v1/hook/28/"
  },
  "data": {
    "project_name": "My Project",
    "name": "d",
    "old_quadrant": 2,
    "quadrant": 3,
    "edited_by_username": "someone@company.com",
    "project_id": 234,
    "id": 123
  }
}

Note that every call to a hook will contain a description of the triggered hook with the fields:

  • resource_uri: API path for the triggered hook
  • event: event that triggered the hook
  • account
  • user: user that created this hook
  • enabled: true if the hook is enabled. All triggered hooks are enabled, if not, they won't trigger.
  • target: url that the hook calls
  • triggered_by: not always present, it denotes the user that did the action that triggered the hook.

Common webhook API operations

  • List current account hooks
    GET /api/v1/hook/
  • Create a new hook for all items
    POST /api/v1/hook/
    Example body: {"event": "item.created", "target": "https://webapp.com/url/"}
  • Create a new hook for project 234
    POST /api/v1/hook/
    Example body: {"event": "item.created", "target": "https://webapp.com/url/", "project": /api/v1/project/234/}
  • Update a hook (with ID 28)
    PUT /api/v1/hook/28/
    In the body include only the fields to be modified, for example {"project": /api/v1/project/234/} or {"target": "https://webapp.com/new_url/"}.
  • Disable a hook
    PUT /api/v1/hook/28/ with {"enabled": false}.
  • Delete a hook
    DELETE /api/v1/hook/28/