Skip to main content

MetaPulse API v4

MetaPulse provides a simple API for you to list, read, create, update member and data.

Written by Support

Domain Change

In Nov 2021 we changed our name from envisage to MetaPulse. The new domain is metapulse.com. Although the API will work on both metapulse.com and envisage.io, the latter is deprecated, therefore we recommend upgrading all API calls to metapulse.com


MetaPulse has a simple API that is available for your use, any feedback is welcome. 

This document represents version 4 of the API. You can find all versions listed in our help article: See all API Versions

You can use the API to programmatically list, read, create, update and destroy data points against your graphs and members.  For rate limits see MetaPulse API Usage Limits.

Sections:

Setup

_______________________________________

To begin, you will need the email you use to sign into MetaPulse along with the API key from your MetaPulse User Profile page.  

If you will be doing a lot of API calls, it is best practice to create an API user in MetaPulse and give this user profile the permissions needed to access the necessary graphs.  
​ 
While you can use your own email and API key, a dedicated API user account is recommended.

Testing Authentication

_______________________________________

The first test you should do is make sure you can authenticate with the server. MetaPulse uses header based authentication, so you need to set two headers in your request: API-EMAIL  and API-KEY . The email is your user email, the API key is from your profile page. 

You can check authentication is working by doing the following command using the curl system utility:

curl -i \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     https://metapulse.com/api/v4/authentication

Which should give you a 200 OK with an empty body looking something like:

HTTP/2 200 
date: Mon, 07 Jan 2019 02:35:35 GMT
content-type: text/html
...

This 200 OK means you have successfully connected to the server.

Using the Data Point API
_______________________________________

Available Data Point API actions:

Note all following date formats are YYYY-MM-DD 

You can find the Graph ID (token) on the graphs page under the Graph Info menu option.

List All Data Points

The following lists all data points for a single graph. Values are returned in order of oldest to most recent.

curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X GET \
     https://metapulse.com/api/v4/data_points?graph_id=<GRAPH_TOKEN>

So for example, if your API_EMAIL  was user@example.com  and your API_KEY  was sdlexamplekfj  and you wanted the data points for a weekly graph with the week ending on Thursday which had the graph token gra2example3 then the full command would be:

curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
     -X GET \
     https://metapulse.com/api/v4/data_points?graph_id=gra2example3

Which would return a JSON array looking something like this:

[
  {
    "graphToken": "gra2example3",
    "majorEvent": false,
    "note": null,
    "periodEnd": "2018-11-9",
    "periodStart": "2018-11-15",
    "value": "2.0",
"updaterEmail": "bob@example.com",
"createdAt": "2018-11-16T09:14:54.133+10:00"
"updatedAt": "2018-11-16T09:14:54.133+10:00"
  },
  {
    "graphToken": "gra2example3",
    "majorEvent": false,
    "note": "We launched the product this week!",
    "periodEnd": "2018-11-16",
    "periodStart": "2018-11-22",
    "value": "4.0",
"updaterEmail": "bob@example.com",
"createdAt": "2018-11-23T09:14:05.894+10:00",
"updatedAt": "2018-11-23T09:14:05.894+10:00"
  },
  {
    "graphToken": "gra2example3",
    "majorEvent": false,
    "note": null,
    "periodEnd": "2018-11-23",
    "periodStart": "2018-11-29",
    "value": "5.0",
"updaterEmail": "bob@example.com",
"createdAt": "2018-11-30T09:14:23.276+10:00",
"updatedAt": "2018-11-30T09:14:23.276+10:00"
  },
  ...
]

This will return up to 50 data points at a time. You can fetch the next set of results by passing the page  parameter. For example: /api/v4/data_points?page=2. You can also customize the number of results by passing per_page=100 up to 500 results per request.

List All Data Points Using Timestamp

You can use the following parameters to list data points for a specific period:

  • starts_after Returns data points where the period starts after the given date.

  • starts_on_or_after Returns data points where the period starts on or after the given date.

  • starts_before Returns data points where the period starts before the given date.

  • starts_on_or_before Returns data points where the period starts on or before the given date.

  • ends_after Returns data points where the period ends after the given date.

  • ends_on_or_after Returns data points where the period ends on or after the given date.

  • ends_before Returns data points where the period ends before the given date.

  • ends_on_or_before Returns data points where the period ends on or before the given date.

You can use it like this:

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \

/api/v4/data_points?graph_id=<TOKEN>&starts_after=2023-01-01&ends_on_or_before=2023-02-01


You can pass created_after and updated_after passing a timestamp to only retrieve records that have been created or updated after the specified timestamp.

When updated_after or created_after is used the records are returned in order of news to oldest.

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \

https://metapulse.com/api/v4/data_points?graph_id=<TOKEN>&created_after=2023-01-01


/** Or Use updated_after **/
https://metapulse.com/api/v4/data_points?graph_id=<TOKEN>&updated_after=2023-01-01

Show a Data Point

To view details for a specific data point, pass the date into the path:

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
https://metapulse.com/api/v4/data_points/2018-11-28?graph_id=<TOKEN>

This would return the following response:

{
"graphToken": "<GRAPH_TOKEN>",
"majorEvent": false,
"note": null,
"periodEnd": "2018-11-28",
"periodStart": "2018-11-28",
"value": "12.0",
"updaterEmail": "bob@example.com",
"createdAt": "2018-11-30T09:14:23.276+10:00",
"updatedAt": "2018-11-30T09:14:23.276+10:00"
}

Create or Update a Data Point

To set the value for a data point, run the following command:

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{"graph_id":"<GRAPH_TOKEN>","period":"2018-11-28","value":"15"}' \
https://metapulse.com/api/v4/data_points/set

This would set the value on 28th of November, 2018 to equal 15, creating it if it does not exist or updating it if it does exist. This would respond with:

{
"graphToken": "<GRAPH_TOKEN>",
"majorEvent": false,
"note": null,
"periodEnd": "2018-11-28",
"periodStart": "2018-11-28",
"value": "15.0",
"updaterEmail": "bob@example.com",
"createdAt": "2018-11-30T09:14:23.276+10:00",
"updatedAt": "2018-11-30T09:14:23.276+10:00"
}

If there is an error setting the data point, you will receive a 400 Bad Request with an error message.

{"error": {"message": "Graph is archived"}} 

Split a Weekly Data Point Across Two Months

It is possible to split a data point into two values if you have a weekly graph and the period spans two months. One value is assigned to the first month and another to the second month.

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{"graph_id":"<GRAPH_TOKEN>","period":"2018-11-02","earlier_split_value":"10","later_split_value":"5"}' \
https://metapulse.com/api/v4/data_points/set

In this example the organization's week ends on a Friday. The data point period is for the 27th of October through the 2nd of November, 2018. The value 10 would be assigned to the October portion and 5 would be assigned to the November portion of the week.

Delete a Data Point

To delete a data point, pass an empty value.

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{"graph_id":"<GRAPH_TOKEN>","period":"2018-11-28","value":""}' \
https://metapulse.com/api/v4/data_points/set

That for example would remove the value on 28th of November, 2018.

Set Multiple Data Points at Once

You can set multiple data points in a single request by supplying an array of data point values. This will create the data point if it does not exist and update the value if it does exist. If you pass an empty value it will delete the data point.

NOTE: You need to have edit permission level for all graphs you are trying to update with set_multiple

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{
"data_points": [
{"graph_id": "gra123","value": "14","period": "2018-11-28"},
{"graph_id": "gra123","value": "","period": "2018-11-29"}
]
}' \
https://metapulse.com/api/v4/data_points/set_multiple


For example, this would set the value on 28th of November, 2018 to equal 14 and delete the data point on the 29th.

This would return the following output:

HTTP/2 200 
date: Mon, 07 Jan 2019 03:04:49 GMT
content-type: application/json
...

If you need to set multiple datapoints for the same date, pass the period separately in the same /api/v4/data_points/set_multiple request.

{
"period": "2019-01-01",
"data_points": [
{"graph_id": "gra12345", "value": 1},
{"graph_id": "gra34567", "value": 2, "note": "Some note"},
{"graph_id": "gra56789", "value": 3, "period": "2019-02-01"}
]
}

Note the last data point has a period. This will override the initial period passed in. Any data points which don't have a period fall back to that global period.

Also, this behaves the same as the set action, so it will:

  • Create a data point if it doesn't exist

  • Update a data point if it already exists

  • Delete a data point if it exists and the given value is empty

Data Point Options

The following options can be passed in when setting a data point.

graph_id (required)

The Graph ID (token) the data point belongs to.

period (required)

The date the data point is on.

value

The decimal value assigned to the data point.

earlier_split_value

The first part of the value if it is a weekly period which covers two months.

later_split_value

The last part of the value if it is a weekly period which covers two months.

note

The note attached to the data point.

append_note

Extra content to add to an existing note.

major_event

Boolean true or false depending on if it is a major event.

skip_expected_value_check

Set to false if you want to return an error when the value is outside the expected range.

Increment a Data Point

You can increment a data point for the 28th of November, 2018 by 1, creating it if it does not exist and setting it to the value of 1 or updating it by 1 if it does. Passing in a note value will append it to the existing note (if any) joined with a new line.

To do this, you would run the following command: 

curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X PATCH \
     -d '{"graph_id":"<GRAPH_TOKEN>","value":"1","note":"Second Note","period":"2018-11-28"}' \
     https://metapulse.com/api/v4/data_points/increment

Which would give you in response if the graph already had the value of 15 and note of "First Note":

{
  "graphToken": "<GRAPH_TOKEN>",
  "majorEvent": false,
  "note": "First Note\nSecond Note",
  "periodEnd": "2018-11-28",
  "periodStart": "2018-11-28",
  "value": "16.0",
"updaterEmail": "bob@example.com",
"createdAt": "2018-11-30T09:01:32.921+10:00"
"updatedAt": "2018-11-30T09:14:23.276+10:00"
}

Note, passing a negative value will decrement the data point by the amount given.

Using the Graphs API 

_______________________________________

Available Graph API actions:

Create a Graph

POST /api/v4/graphs HTTP/1.1
Host: metapulse.com
Content-Type: application/json

{
"organisation_token": "abc123",
"graph": {
"name": ,
"graph_type": "weekly",
"responsible_member_email": "name@email.com"
}
}

The organisation_token is the same as the "Organization ID" found on the organization settings.

If you want to add additional graph attributes while creating a graph, here's the full list:

name

Name of the graph

description

You can add a description for the graph

graph_type (only when creating a graph)

daily, weekly, monthly, quarterly, yearly, comparison, calculated or concatenated

display_frequency

daily, weekly, monthly, quarterly or yearly

inverted

true or false

responsible_member_email

To assign the graph to a member, you need to provide the member's email address.

decimal_places

1, 2, 3, etc.

viability_line

true or false

unit_symbol

any symbol

unit_position

left or right. This will place the symbol on the left or right side of the value.

scale_minimum

You can set a minimum value for the graph. If there is a value outside of this scope, the scope will be ignored.

scale_maximum

You can set a maximum value for the graph. If there is a value outside of this scope, the scope will be ignored.

missing_data_treatment

gap, zero or hide

hidden

true or false

permission_level

none, view, add, edit or admin

show_values_on_graph

true or false

show_incomplete_values

true or false

aggregate_method

It determines how values are displayed at lower frequencies. For example, it can display all values in the period, the average of all values, the minimum / maximum value within the period, the first or last reported value of the period. The values are sum, average, minimum, maximum, first or last

data_collection_days

It's useful when daily graphs are used. It will collect data on all or specific days. The format is [false, true, true, true, true, true, false] in which a value is specified for each day. In the above example, it will collect data on Tuesday, Wednesday, Thursday, Friday and Saturday. Sunday and Monday are omitted because they are set to false.

connect_incomplete_period

true or false

Search for a list of Graphs

MetaPulse has a power search function in the Graphs Index API. 

Both graph names and user names can be searched.

The follow code returns all graphs with the term "Income" in the name.

Note, this also will returns any graph with an associated user that has the search term in their name.

curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X GET \
     https://metapulse.com/api/v4/graphs?term=Income

Which should return 200 OK with an array of the graph tokens, names and graph type that match the search: 

[
  {
    "token": "grawrddq12o",
    "name": "Total Clients",
    "graphType": "weekly",
    "availableFrequencies": ["weekly", "monthly", "quarterly", "yearly"],
"hidden": false,
"archived": false,
    "responsibleMemberFullName": "Bob Smith",
    "responsibleMemberEmail": "bob@example.com",
    "responsibleMemberEmployeeId": "ABC123",
    "customAttributes": [{"name": "Internal ID", "value": "789"}]
  }, {
    "token": "gra8sd2qkez",
    "name": "Gross Income",
    "graphType": "daily",
    "availableFrequencies": ["daily", "weekly", "monthly", "quarterly", "yearly"],
    "hidden": false,
"archived": false,
"createdAt": "2018-11-30T09:01:32.921+10:00"
"updatedAt": "2018-11-30T09:14:23.276+10:00"
    "responsibleMemberFullName": "Jane Smith",
    "responsibleMemberEmail": "jane@example.com",
    "responsibleMemberEmployeeId": "",
    "customAttributes": []
  }
]

The possible list of types returned for graphType are:

  • daily 

  • weekly  

  • monthly 

  • quarterly 

  • yearly 

  • calculated 

  • comparison 

  • concatenated 

This will return up to 50 graphs at a time. You can fetch the next set of results by passing the page parameter. For example: /api/v4/graphs?page=2. You can also customize the number of results by passing per_page=100 up to 500 results per request.

By default only active graphs are returned. Pass include_hidden=true to also return hidden graphs. Pass include_archived=true to also return archived graphs.

Search for a list of Graphs Using Timestamp

You can pass created_after and updated_after passing a timestamp to only retrieve records that have been created or updated after the specified timestamp.

When updated_after or created_after is used the records are returned in order of news to oldest.

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/graphs?term=Income"

"https://metapulse.com/api/v4/graphs?term=Income&created_after=<TIMESTAMP>"

/** Or Use updated_after **/
"https://metapulse.com/api/v4/graphs?term=Income&updated_after=<TIMESTAMP>"

Set Custom Attributes on a Graph

Custom attributes allow you to define your own metadata on a graph. You can set custom attributes on a graph by supplying a name and value:

curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X POST \
     -d '{"graph_id": "grawrddq12o", "name": "Department", "value": "A17"}' \
     "https://metapulse.com/api/v4/graph_custom_attributes"

That example will either create or update the custom attribute "Department" on graph grawrddq12o. For setting a Date Range Type see Setting a Member Custom Attributes with type Date Range.

The graph details will be returned on success:

{
  "token": "grawrddq12o",
  "name": "Total Clients",
  "graphType": "weekly",
  "availableFrequencies": ["weekly", "monthly", "quarterly", "yearly"],
  "hidden": false,
"archived": false,
"createdAt": "2018-11-30T09:01:32.921+10:00"
"updatedAt": "2018-11-30T09:14:23.276+10:00"
  "responsibleMemberFullName": "Bob Smith",
  "responsibleMemberEmail": "bob@example.com",
  "responsibleMemberEmployeeId": "ABC123",
  "customAttributes": [{"name": "Department", "value": "A17"}]
}

Update a Graph

Send a PATCH request to the https://metapulse.com/api/v4/graphs/GRAPH_ID URL to update the graph.

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X PATCH \
-d '{"graph": {"name": "Updated Name", "responsible_member_email": "name@email.com"}}'
} \
https://metapulse.com/api/v4/graphs/gra12345

This would change the graph name and responsible member assigned to the graph matching the ID gra12345.

Delete a Graph

Graphs can be deleted through the API. You need to pass a DELETE method to the https://metapulse.com/api/v4/graphs/[GRAPH_ID] URL. For example:

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X DELETE \
https://metapulse.com/api/v4/graphs/[GRAPH_ID]

Using the Member Graphs API

_______________________________________

Available Member Graphs API actions:

List all viewable Graphs for a Member 

To get a list of all graph tokens and the graph names viewable by a given user email, you can run the following command: 

export params="email=mikel@reinteractive.net&type=viewable"
curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X GET \
     "https://metapulse.com/api/v4/member_graphs?${params}"

Which should return 200 OK with an array of the graph tokens, names and graph type that the user is able to edit: 

[
  {
    "token": "grawrddq12o",
    "name": "Total Clients",
    "graphType": "weekly",
    "hidden": false,
"archived": false,
"createdAt": "2018-10-12T11:21:13.209+10:00"
"updatedAt": "2018-10-13T17:12:43.847+10:00"
    "responsibleMemberEmail": "bob@example.com",
    "responsibleMemberEmployeeId": ""
  }, {
    "token": "gra8sd2qkez",
    "name": "Gross Income",
    "graphType": "daily",
    "hidden": false,
"archived": false,
"createdAt": "2018-11-30T09:01:32.921+10:00"
"updatedAt": "2018-11-30T09:14:23.276+10:00"
    "responsibleMemberEmail": "jane@example.com",
    "responsibleMemberEmployeeId": ""
  }
]

The possible list of types returned for graphType are:

  • daily 

  • weekly  

  • monthly 

  • quarterly 

  • yearly 

  • calculated 

  • comparison 

  • concatenated 

You can also specify the member using their Employee ID field if set:

export params="employee_id=ABC123&type=viewable"
curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X GET \
     "https://metapulse.com/api/v4/member_graphs?${params}"

This will return up to 50 graphs at a time. You can fetch the next set of results by passing the page parameter. For example: /api/v4/member_graphs?page=2. You can also customize the number of results by passing per_page=100 up to 500 results per request.

Note, you can pass created_after and updated_after passing a timestamp to only retreive records that have been created or updated after the specified timestamp.

List all editable Graphs for a Member 

To get a list of all graph tokens and the graph names that the given member can edit, pass the type=editable parameter, for example: 

export params="email=mikel@reinteractive.net&type=editable"
curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X GET \
     "https://metapulse.com/api/v4/member_graphs?${params}"

This will return the same output as listing the viewable graphs above.

List all responsible Graphs for a Member 

To get a list of all graph tokens and the graph names that the given member is responsible for, pass the type=responsible parameter, for example: 

export params="email=mikel@reinteractive.net&type=responsible"
curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X GET \
     "https://metapulse.com/api/v4/member_graphs?${params}"

This will return the same output as listing the viewable graphs above.

List all Graphs for a Member Using Timestamp

You can pass created_after and updated_after passing a timestamp to only retrieve records that have been created or updated after the specified timestamp.

When updated_after or created_after is used the records are returned in order of news to oldest.

export params="email=mikel@reinteractive.net&type=editable"
curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/member_graphs?${params}"

"https://metapulse.com/api/v4/member_graphs&type=responsible&created_after=<TIMESTAMP>"

/** Or Use updated_after **/
"https://metapulse.com/api/v4/member_graphs&type=responsible&updated_after=<TIMESTAMP>"

Using the Members API

_______________________________________

Available Member API actions:

List members under an organization

You can fetch members for an organization using the following:

See Organisation ID to get the ORGANISATION_TOKEN.

export params="organisation_id=<ORGANISATION_TOKEN>"
curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X GET \
     "https://metapulse.com/api/v4/members?{params}"

List members under an organization - Example Request

# GET https://metapulse.com/api/v4/members?organisation_id=orgmvn0c5uy

This will return the following fields for each member:

{
"id": "memi5vgbo31",
"email": "harry@example.com",
"fullName": "Harry Cash",
"phoneNumber": "",
"phoneExtension": "",
"mobileNumber": "",
"employeeId": "",
"status": "Permanent",
"hireDate": null,
"avatar": "https://staging-assets.metapulse.com/uploads/member/avatar/245/1728503930-980549575293776-0001-4252/avatar.png",
"avatarMedium": "https://staging-assets.metapulse.com/uploads/member/avatar/245/medium_1728503930-980549575293776-0001-4252/avatar.png",
"avatarSmall": "https://staging-assets.metapulse.com/uploads/member/avatar/245/small_1728503930-980549575293776-0001-4252/avatar.png",
"avatarThumb": "https://staging-assets.metapulse.com/uploads/member/avatar/245/thumb_1728503930-980549575293776-0001-4252/avatar.png",
"countryCode": "",
"countryName": "",
"state": null,
"city": "",
"building": "",
"floorName": "",
"floorSection": "",
"timeZone": "Sydney",
"postId": "posdb5a2hhq",
"postName": "Sales Director",
"positionId": "posdb5a2hhq",
"positionName": "Sales Director",
"orgNodeName": "Sales",
"teamLeader": true,
"assistant": false,
"managerEmail": "ceo@example.com",
"notificationEmailFrequency": "hourly",
"saml": false,
"archivedAt": null,
"createdAt": "2020-03-23T06:19:24.060Z",
"updatedAt": "2025-04-14T17:50:22.931Z",
"ancestryPath": [
{
"id": "uniw0xykhuv",
"name": "Building HQ USA",
"post": "1.",
"position": "1."
},
{
"id": "uniqup68j6m",
"name": "Sales",
"post": "1.C.",
"position": "1.C."
}
],
"customAttributes": [
{
"name": "Formal Given Name",
"type": "text",
"value": "Harry"
},
{
"name": "Formal Family Name",
"type": "text",
"value": "Cash"
}
]
}

This will return up to 50 members at a time. You can fetch the next set of results by passing the page  parameter. For example: /api/v4/members?page=2. You can also customize the number of results by passing per_page=100 up to 500 results per request.

Note, you can pass created_after and updated_after passing a timestamp to only retreive records that have been created or updated after the specified timestamp.

The Ancestry Path will return a JSON array of all positions from the top of their organization chart all the way down to the member's highest position. This provides a way to determine what area each member is in.

List members under another member

It's possible to fetch members overseen by another member by passing the overseen_by parameter.

export params="organisation_id=<ORGANISATION_TOKEN>&overseen_by=<EMAIL>"
curl -i \
     -H "Content-Type: application/json" \
     -H "Accept: application/json" \
     -H "api-email: <API_EMAIL>" \
     -H "api-key: <API_KEY>" \
     -X GET \
     "https://metapulse.com/api/v4/members?{params}"

List members under another member - Example Request

# GET https://metapulse.com/api/v4/members?organisation_id=orgmvn3c2mz&overseen_by=harry@example.com

List members under another member - Example Response

[
{
"id": "mem5ikznbgx",
"email": "bob@example.com",
"fullName": "Bob Builder",
"phoneNumber": "1-769-854-2688",
"phoneExtension": "",
"mobileNumber": "",
"employeeId": "",
"status": "",
"hireDate": null,
"avatar": "https://staging-assets.metapulse.com/uploads/user/avatar/1/avatar(2).png",
"avatarMedium": "https://staging-assets.metapulse.com/uploads/user/avatar/1/medium_avatar(2).png",
"avatarSmall": "https://staging-assets.metapulse.com/uploads/user/avatar/1/small_avatar(2).png",
"avatarThumb": "https://staging-assets.metapulse.com/uploads/user/avatar/1/thumb_avatar(2).png",
"countryCode": "",
"countryName": "",
"state": null,
"city": "",
"building": "",
"floorName": "",
"floorSection": "",
"timeZone": "UTC",
"postId": "posjc2gavav",
"postName": "Director of Marketing",
"positionId": "posjc2gavav",
"positionName": "Director of Marketing",
"orgNodeName": "Sales",
"teamLeader": false,
"assistant": false,
"managerEmail": "harry@example.com",
"notificationEmailFrequency": "immediately",
"saml": false,
"archivedAt": null,
"createdAt": "2018-10-15T06:28:12.678Z",
"updatedAt": "2025-04-03T20:13:53.084Z",
"ancestryPath": [
{
"id": "uniw0xykhuv",
"name": "Building HQ USA",
"post": "1.",
"position": "1."
},
{
"id": "uniqup68j6m",
"name": "Sales",
"post": "1.C.",
"position": "1.C."
}
],
"customAttributes": []
},
{
"id": "mem2uc32jud",
"email": "sarah@example.com",
"fullName": "Sarah Black",
"phoneNumber": "",
"phoneExtension": "",
"mobileNumber": "",
"employeeId": "",
"status": "Permanent",
"hireDate": null,
"avatar": "https://staging-assets.metapulse.com/uploads/member/avatar/246/sarah_black.jpg",
"avatarMedium": "https://staging-assets.metapulse.com/uploads/member/avatar/246/medium_sarah_black.jpg",
"avatarSmall": "https://staging-assets.metapulse.com/uploads/member/avatar/246/small_sarah_black.jpg",
"avatarThumb": "https://staging-assets.metapulse.com/uploads/member/avatar/246/thumb_sarah_black.jpg",
"countryCode": "AU",
"countryName": "Australia",
"state": "",
"city": "",
"building": "",
"floorName": "",
"floorSection": "",
"timeZone": "Sydney",
"postId": "posjlir7x8o",
"postName": "Director of Sales",
"positionId": "posjlir7x8o",
"positionName": "Director of Sales",
"orgNodeName": "Sales & Marketing",
"teamLeader": false,
"assistant": false,
"managerEmail": null,
"notificationEmailFrequency": "immediately",
"saml": false,
"archivedAt": null,
"createdAt": "2020-03-23T08:44:53.186Z",
"updatedAt": "2025-02-24T23:17:16.210Z",
"ancestryPath": [
{
"id": "uninubczmok",
"name": "CEO",
"post": "1.",
"position": "1."
},
{
"id": "uniqvo8df9t",
"name": "Sales & Marketing",
"post": "1.C.",
"position": "1.C."
}
],
"customAttributes": [
{
"name": "Formal Given Name",
"type": "text",
"value": "Sarah"
},
{
"name": "Formal Family Name",
"type": "text",
"value": "Black"
}
]
}

This will return a list of members which are under that given member in the Team Chart.

Show a Specific Member

After you get the Member ID from the List action, or from the Manage Member Page, you can request details for an individual member as follows:

export email="<API_EMAIL>"
export key="<API_KEY>"
export memberid="<MEMBER_ID>" # eg, memaqt2owd7
export params="organisation_id=<ORGANISATION_TOKEN>"

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: ${email}" \
-H "api-key: ${key}" \
-X GET \
"https://metapulse.com/api/v4/members/{memberid}?{params}"

Show a Specific Member - Example Request

# GET https://metapulse.com/api/v4/members/mem3p3rlk8f?organisation_id=orgmvn0c5uy

This will return the same attributes as shown in Member Example Response.

Set Custom Attributes for a Member

Using the Member ID (mem12345678) obtained via the List action above, or from the Members Data Export, you can update the member's Custom Attributes as follows:

curl -i \      
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{"name": "Department", "value": "A17"}' \
"https://metapulse.com/api/v4/members/<MEMBER_ID>/custom_attributes"

Setting a Member Custom Attributes with type Date Range

Here's syntax for setting a Date Range:

 curl -i \      
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{"name": "On Leave", "value": {"start_date":"2022-01-01","end_date":"2022-02-13"}}' \
"https://metapulse.com/api/v4/members/<MEMBER_ID>/custom_attributes"


Updating Member Attributes

Using the Member ID (mem12345678) obtained from the Members Data Export, you can update any of of the following member attributes:

Status

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"status": "Contractor"
}
}

The status options are "Permanent", "Contractor", "Intern" and "Trial".

Email

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"email": "harry@example.com"
}
}

Employee ID

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"employee_id": "B17"
}
}

Hire Date

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"hire_date": "2024-06-01"
}
}

Full Name

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"full_name": "Harry Cash"
}
}

Phone Number

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"phone_number": "+16225349475"
}
}

Phone Extension

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"phone_extension": "23"
}
}

Mobile Number

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"mobile_number": "+18215349726"
}
}

Country

(The country ISO code needs to be entered. Only two characters are accepted. For full list of all country ISO codes, see https://countrycode.org/)

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"country_code": "US"
}
}

State

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"state": "Florida"
}
}

City

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"city": "Miami"
}
}

Building

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"city": "Miami"
}
}

Floor Name

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"floor_name": "Research"
}
}

Floor Section

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"floor_section": "Marketing"
}
}

Time Zone

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"time_zone": "Eastern Time (US & Canada)"
}
}

List of accepted time zones (see "TZ identifier" column):

Add Avatar

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"remote_avatar_url": "https://images.com/photos/photo-2259337.jpeg"
}
}

Remove Avatar (True/False, true to remove)

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"remove_avatar": true
}
}

SAML

(True/False. It can only be set if SAML is enabled on the account and the user is restricted to that account.)

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"allow_saml": true
}
}

Restrict User to an Account

(True/False, if it's the user's only account)

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"restrict_to_current_account": true
}
}

Email Alerts

(This is for sending a notification when an Alert is created. It should be true or false and the member being set needs to have permission to view alerts.)

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"email_alerts": true
}
}

Send Invitation

(You can only set this on new members. It doesn't work on existing members. It should be true or false. )

POST https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"organisation_id": "orgvev3c5uy",
"member": {
"email": "bob@example.com",
"full_name": "Bob Cat",
"send_invitation": true
}
}

Scheduled Mailings and Reminders

This refers to the following four reminders:

For this to work, you would need to set it to Custom Mailings and then enable/disable the desired reminder. Here's an example:

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{"member":
{
"mailings_preference": "custom",

"mailing_settings_attributes": [
{
"email_template_id": "07ad2013-8105-49ac-b82f-49acc4c18b75",
"enabled": false
},
{
"email_template_id": "794e2b80-42bf-4acb-ac69-51bw276c7ac1",
"enabled": false
},
{
"email_template_id": "a117bb21-b52a-4c12-82d5-f649bf78b0c4",
"enabled": false
},
{
"email_template_id": "79bf6m09-6678-4c79-b8fe-b9126c47af7a",
"enabled": false
}
]
}
}

To get the Email Template IDs, you would need to export the Email Templates from the Data Export page.

Email Frequency Notification (can be never, immediately, hourly, daily or weekly)

This refers to the following setting:

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member": {
"notification_email_frequency": "immediately"
}
}

Customize Individual Notifications

This refers to all predefined email notifications that are being sent when a specific event is triggered, such as when a Knowledge Item is created or a Graphs View is shared with another member, etc.

These notification relate to Knowledge, Alerts, Data Import, Data Export and Views (Knowledge, Objectives or Graphs.):

PATCH https://metapulse.com/api/v4/members/<MEMBER_ID>
{
"member":
{
"email_notification_settings":
{
"0": {
"type_key": "knowledge_approval_step_pending",
"frequency": "hourly"
},
"1": {
"type_key": "knowledge_approval_step_pending",
"frequency": "hourly"
},
"2": {
"type_key": "knowledge_approval_requested",
"frequency": "hourly"
}
}
}
}

Here, they keys "0" and "1" don't have any special meaning, they just need to be unique.

The above example only includes 3 types. Here's a list of all of them, including the available frequencies:

The type_key can be one of:

  • knowledge_approval_step_pending

  • knowledge_approval_requested

  • knowledge_item_version_approved

  • knowledge_item_version_published

  • knowledge_assignment_created

  • knowledge_assignment_updated

  • knowledge_assignment_manually_created

  • knowledge_assignments_multiple_created

  • knowledge_assignment_completed

  • knowledge_subject_assignment_created

  • knowledge_collaborator_added

  • knowledge_collaboration_request

  • knowledge_comment_created

  • knowledge_comment_mention

  • knowledge_periodic_reviews_due

  • knowledge_periodic_reviews_overdue

  • alert_created_confirmation

  • alert_assigned

  • data_import_succeeded

  • data_import_failed

  • data_export_succeeded

  • data_export_failed

  • view_shared

And the frequency can be one of:

  • never

  • immediately

  • hourly

  • daily

  • weekly

If the update is successful, the response will be 200 with the member details (same as GET member). If there's a validation error the response will be 400 error code with JSON body. Here's an example:

{
"errors": {
"message": "Unable to save member due to the following error: Email is invalid"
}
}

Show Away Periods

Show Away Periods for a Member

List

Returns array of away periods for a given member.

Show Away Periods for a Member - Example Request

# GET https://metapulse.com/api/v4/member/[MEMBER_ID]/away_periods

Show Away Periods for a Member - Example Response

[
{
"id": "e1957d54-bf87-4d1a-8aa1-d71d0563ddae",
"startDate": "2022-01-01",
"endDate": "2022-02-02",
"reason": "Holiday"
}
]

Show

Returns data for a single away period given an ID. Note the ID is in the URL.

Show a Single Away Period for a Member - Example Request

# GET https://metapulse.com/api/v4/member/[MEMBER_ID]/away_periods/[AWAY_PERIOD_ID]

Show a Single Away Period - Example Response

{ 
"id": "e1957d54-bf87-4d1a-8aa1-d71d0563ddae",
"startDate": "2022-01-01",
"endDate": "2022-02-02",
"reason": "Holiday",
}

Create

Creates an away period given attributes.

Create a Single Away Period - Example Request

# POST https://metapulse.com/api/v4/member/[MEMBER_ID]/away_periods
{
"away_period": {
"start_date": "2022-01-01",
"end_date": "2022-02-02",
"reason": "Holiday"
}
}

Create a Single Away Period - Example Success Response

Same as "Show" above

Create a Single Away Period - Example Failure Response

# Returns 400 bad request
{"error":{"message":"Unable to save away period: Start Date can't be blank."}}

Update

Updates an away period given id and attributes.

Update a Single Away Period - Example Request

# PATCH https://metapulse.com/api/v4/member/[MEMBER_ID]/away_periods/[AWAY_PERIOD_ID]
{
"away_period": {
"start_date": "2022-01-01",
"end_date": "2022-02-02",
"reason": "Holiday"
}
}

Example Success Response

Same as "Show" above

Example Failure Response

Same as "Create" above

Destroy

Deletes an away period given id.

Delete a Single Away Period - Example Request

# DELETE https://metapulse.com/api/v4/member/[MEMBER_ID]/away_periods/[AWAY_PERIOD_ID]

Example Response

Nothing (200 OK)

Show Away Periods for all Members

List

Returns all away periods for a given organization.

Show Away Periods for all Members - Example Request

# GET https://metapulse.com/api/v4/members/away_periods/?organisation_id=[ORGANIZATION_ID]

Show Away Periods for all Members - Example Response

[
{
"id": "07e48750-b935-4e34-a24f-81b36bd830bb",
"startDate": "2022-10-10",
"endDate": "2022-10-15",
"reason": "Vacation",
"memberId": "memqomqq6z1",
"memberEmail": "sally@example.com"
},
{
"id": "bc6dfde0-ae30-4f69-84f1-d8c15654689a",
"startDate": "2024-06-15",
"endDate": "2024-06-21",
"reason": "Vacation",
"memberId": "mem1x1843ct",
"memberEmail": "bill@example.com"
},
{
"id": "fac08ea7-b927-470e-849c-aa02ecdf88f3",
"startDate": "2024-08-12",
"endDate": "2024-08-22",
"reason": "Vacation",
"memberId": "mem1st9w5wz",
"memberEmail": "kim@example.com"
}
]

If there are too many, you can split them in pages. The limit per page is 500.

Show Away Periods for all Members Page by Page - Example Request

# GET https://metapulse.com/api/v4/members/away_periods?page=2&per_page=500

Create a member

Create a member - Example Request

# POST https://metapulse.com/api/v4/members/
{
"organisation_id": "orgt5omjbsk",
"member": {
"email": "bobcat@example.com",
"full_name": "Bob Cat"
}
}

Create a member - Example Response

{
"id": "mem2drlgc88",
"email": "bobcat@example.com",
"fullName": "Bob Cat",
"phoneNumber": null,
"phoneExtension": null,
"mobileNumber": null,
"employeeId": null,
"status": null,
"hireDate": null,
"avatar": null,
"avatarMedium": null,
"avatarSmall": null,
"avatarThumb": null,
"countryCode": null,
"countryName": null,
"state": null,
"city": null,
"building": null,
"floorName": null,
"floorSection": null,
"timeZone": "Sydney",
"postId": null,
"postName": null,
"positionId": null,
"positionName": null,
"orgNodeName": null,
"managerEmail": null,
"createdAt": "2024-08-23T17:08:35.613Z",
"updatedAt": "2024-08-23T17:08:35.613Z",
"customAttributes": []
}

Archive a member

Archive a member - Example Request

# POST https://metapulse.com/api/v4/members/<MEMBER_ID>/archive

This will return an empty 200 OK response.

Unarchive a member

Unarchive a member - Example Request

# POST https://metapulse.com/api/v4/members/<MEMBER_ID>/unarchive

This will return an empty 200 OK response.

Using the Team Chart API

Team Charts

The Team Charts API lets you list and read the team charts in an organisation. A team chart is the top-level container for the org structure; it contains teams, which contain positions, which are filled by members.

For an introduction to authentication and the common request format, see the MetaPulse API v4 overview.

All examples assume:

  • API_EMAIL — the email of your MetaPulse user

  • API_KEY — the API key from your MetaPulse user profile

  • ORG_ID — your organisation id (e.g. org12abc3de4)

Every endpoint requires the organisation_id query parameter.

Endpoints

Method

Path

Description

GET

/api/v4/team_charts

List team charts

GET

/api/v4/team_charts/:id

Show a team chart

The Team Chart Object

{   
"id": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"name": "Operations",
"main": true,
"missionStatement": "Deliver a great product to our customers.",
"archivedAt": null,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}

Field

Type

Description

id

UUID

Unique identifier of the team chart.

name

string

Display name.

main

boolean

Whether this is the org's main team chart.

missionStatement

string | null

Free-form mission statement.

archivedAt

timestamp | null

Set when the team chart is archived.

createdAt

timestamp

When the team chart was created.

updatedAt

timestamp

When the team chart was last updated.

List Team Charts

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/team_charts?organisation_id=<ORG_ID>"

Returns a JSON array of team chart objects. Pagination defaults to 50 results per page; pass page and per_page (up to 500) to customise.

[
{
"id": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"name": "Operations",
"main": true,
"missionStatement": "Deliver a great product to our customers.",
"archivedAt": null,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
},
{
"id": "8a2c3d44-1b22-4ee2-9101-7c8a9d0e2b33",
"name": "Sales",
"main": false,
"missionStatement": null,
"archivedAt": null,
"createdAt": "2025-01-20T10:00:00.000+10:00",
"updatedAt": "2025-01-20T10:00:00.000+10:00"
}
]

Show a Team Chart

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/team_charts/<ID>?organisation_id=<ORG_ID>"

Returns a single team chart object, or 404 Not Found if no team chart with that id exists in the organisation.

{
"id": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"name": "Operations",
"main": true,
"missionStatement": "Deliver a great product to our customers.",
"archivedAt": null,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}

Errors

All endpoints return errors in a consistent shape:

{ "error": { "message": "<human-readable message>" } }

Status

When

401 Unauthorized

Missing or invalid api-email / api-key headers, or your user lacks permission for the action.

404 Not Found

The team chart or organisation id doesn't exist or isn't visible to your user.

Teams

The Teams API lets you list, read, create, update, archive and re-parent the teams inside a team chart. A team is a node in the org structure; teams nest under a parent team, and each team holds one or more positions (see the Positions API).

For an introduction to authentication and the common request format, see the MetaPulse API v4 overview.

All examples assume:

  • API_EMAIL — the email of your MetaPulse user

  • API_KEY — the API key from your MetaPulse user profile

  • ORG_ID — your organisation id (e.g. org12abc3de4)

Every endpoint requires the organisation_id query parameter.

Endpoints

Method

Path

Description

GET

/api/v4/teams

List teams

GET

/api/v4/teams/:id

Show a team

POST

/api/v4/teams

Create a team

PATCH

/api/v4/teams/:id

Update a team

POST

/api/v4/teams/:id/archive

Archive a team

POST

/api/v4/teams/:id/unarchive

Unarchive a team

POST

/api/v4/teams/:id/move

Re-parent a team

The Team Object

{
"id": "tea12abc3de4",
"name": "Engineering",
"teamChartId": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"parentId": "tea98zyx7wvu",
"sequence": 0,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}

Field

Type

Description

id

string

Unique id for the team (e.g. tea12abc3de4).

name

string

Display name.

teamChartId

UUID

The team chart this team belongs to.

parentId

string | null

Id of the parent team, or null for a root team.

sequence

integer

Sort order among siblings.

archivedAt

timestamp | null

Set when the team is archived.

draft

boolean

true if the team is in draft (unpublished) state.

createdAt

timestamp

When the team was created.

updatedAt

timestamp

When the team was last updated.

List Teams

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/teams?organisation_id=<ORG_ID>"

Returns a JSON array of team objects. Defaults to active (non-archived) teams, ordered by sequence then id. Pagination defaults to 50 results per page; pass page and per_page (up to 500) to customise.

Query Parameters

Parameter

Description

team_chart_id

Only return teams in the given team chart.

parent_id

Only return teams whose parent is this team. Pass null to return only root teams.

archived

true to return only archived teams, all to return both active and archived. Default: active only.

page

Page number (1-based).

per_page

Page size (default 50, max 500).

[
{
"id": "tea12abc3de4",
"name": "Engineering",
"teamChartId": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"parentId": "tea98zyx7wvu",
"sequence": 0,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
},
{
"id": "tea56def7gh8",
"name": "Design",
"teamChartId": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"parentId": "tea98zyx7wvu",
"sequence": 1,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-16T09:14:54.133+10:00",
"updatedAt": "2025-01-16T09:14:54.133+10:00"
}
]

Show a Team

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/teams/<ID>?organisation_id=<ORG_ID>"

Returns a single team object, or 404 Not Found if no team with that id exists in the organisation.

{
"id": "tea12abc3de4",
"name": "Engineering",
"teamChartId": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"parentId": "tea98zyx7wvu",
"sequence": 0,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}

Create a Team

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{
"team": {
"name": "Engineering",
"team_chart_id": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"parent_id": "tea98zyx7wvu"
}
}' \
"https://metapulse.com/api/v4/teams?organisation_id=<ORG_ID>"

Returns the created team (HTTP 200):

{
"id": "tea12abc3de4",
"name": "Engineering",
"teamChartId": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"parentId": "tea98zyx7wvu",
"sequence": 0,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-01-15T09:14:54.133+10:00"
}

See Errors for the validation failure response.

Body Parameters (under team)

Parameter

Required

Description

name

yes

Display name.

team_chart_id

yes

UUID of the team chart this team belongs to.

parent_id

no

Id of the parent team. Omit (or null) to create a root team.

information

no

Free-form information about the team.

valuable_final_product

no

The team's valuable final product (also accepted as results).

knowledge_item_id

no

Knowledge item linked to this team.

sequence

no

Sort order among siblings.

color

no

Hex color, e.g. "#3366ff".

color_enabled

no

Whether the color is shown on the chart.

elevated

no

Whether the team is displayed as elevated on the chart.

draft

no

Create as a draft (unpublished) team. Create-only; ignored on update.

Update a Team

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X PATCH \
-d '{ "team": { "name": "Product Engineering" } }' \
"https://metapulse.com/api/v4/teams/<ID>?organisation_id=<ORG_ID>"

Accepts the same body parameters as create, except draft (which is create-only). Returns the updated team (HTTP 200):

{
"id": "tea12abc3de4",
"name": "Product Engineering",
"teamChartId": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"parentId": "tea98zyx7wvu",
"sequence": 0,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-10T14:32:01.554+10:00"
}

See Errors for the validation failure response.

Archive a Team

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
"https://metapulse.com/api/v4/teams/<ID>/archive?organisation_id=<ORG_ID>"

Returns HTTP 200 with an empty body. A team can only be archived when it has no active children and no active aliases; attempting to archive a team that violates either constraint returns 401 Unauthorized.

Unarchive a Team

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
"https://metapulse.com/api/v4/teams/<ID>/unarchive?organisation_id=<ORG_ID>"

Returns HTTP 200 with an empty body. The team must currently be archived; unarchiving an already-active team returns 401 Unauthorized.

Move a Team

Re-parents the team. Pass parent_id at the top level (not nested under team).

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{ "parent_id": "tea98zyx7wvu" }' \
"https://metapulse.com/api/v4/teams/<ID>/move?organisation_id=<ORG_ID>"

Pass "parent_id": null to make the team a root team. Returns the updated team (HTTP 200):

{
"id": "tea12abc3de4",
"name": "Engineering",
"teamChartId": "6f9f2b1c-3d4e-4a55-9c12-2f3b8e2a1d7e",
"parentId": "tea98zyx7wvu",
"sequence": 0,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-10T14:32:01.554+10:00"
}

Returns 404 Not Found if the parent id can't be found in the organisation.

Errors

All endpoints return errors in a consistent shape:

{ "error": { "message": "<human-readable message>" } }

Status

When

400 Bad Request

Validation failure on create/update/move (e.g. blank name, unknown team_chart_id).

401 Unauthorized

Missing or invalid api-email / api-key headers, or your user lacks permission for the action.

404 Not Found

The team, parent team, or organisation id doesn't exist or isn't visible to your user.

Example validation error from create or update:

{ "error": { "message": "Unable to save team due to the following error: Name can't be blank" } } 

Roles

The Roles API lets you list, read, create and update the roles in an organisation. A role is a reusable job description; positions (see the Positions API) reference a role.

For an introduction to authentication and the common request format, see the MetaPulse API v4 overview.

All examples assume:

  • API_EMAIL — the email of your MetaPulse user

  • API_KEY — the API key from your MetaPulse user profile

  • ORG_ID — your organisation id (e.g. org12abc3de4)

Every endpoint requires the organisation_id query parameter.

Endpoints

Method

Path

Description

GET

/api/v4/roles

List roles

GET

/api/v4/roles/:id

Show a role

POST

/api/v4/roles

Create a role

PATCH

/api/v4/roles/:id

Update a role

The Role Object

{
"id": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"name": "Engineer",
"displayName": "Software Engineer",
"purpose": "Build and maintain the product.",
"function": "Writes, reviews, and ships code.",
"results": "Working features delivered to customers.",
"teamLeader": false,
"assistant": false,
"graphPermissionLevel": "view",
"knowledgeItemId": null,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}

Field

Type

Description

id

UUID

Unique identifier of the role.

name

string

Internal name (must be unique within the organisation).

displayName

string | null

Display name shown on the chart.

purpose

string | null

The role's purpose.

function

string | null

The role's function.

results

string | null

The role's valuable final product / expected results.

teamLeader

boolean

Whether members in this role lead the team they sit on.

assistant

boolean

Whether members in this role are assistants to the team leader.

graphPermissionLevel

string

Default permission level for graphs. One of none, view, edit, admin.

knowledgeItemId

UUID | null

Knowledge item linked to this role.

createdAt

timestamp

When the role was created.

updatedAt

timestamp

When the role was last updated.

List Roles

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/roles?organisation_id=<ORG_ID>"

Returns a JSON array of role objects, ordered by name. Pagination defaults to 50 results per page; pass page and per_page (up to 500) to customise.

Query Parameters

Parameter

Description

team_id

Only return roles that have at least one position on this team.

member_id

Only return roles that the given member fills via at least one position.

page

Page number (1-based).

per_page

Page size (default 50, max 500).

[
{
"id": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"name": "Engineer",
"displayName": "Software Engineer",
"purpose": "Build and maintain the product.",
"function": "Writes, reviews, and ships code.",
"results": "Working features delivered to customers.",
"teamLeader": false,
"assistant": false,
"graphPermissionLevel": "view",
"knowledgeItemId": null,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}
]

Show a Role

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/roles/<ID>?organisation_id=<ORG_ID>"

Returns a single role object, or 404 Not Found if no role with that id exists in the organisation.

{
"id": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"name": "Engineer",
"displayName": "Software Engineer",
"purpose": "Build and maintain the product.",
"function": "Writes, reviews, and ships code.",
"results": "Working features delivered to customers.",
"teamLeader": false,
"assistant": false,
"graphPermissionLevel": "view",
"knowledgeItemId": null,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}

Create a Role

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{
"role": {
"name": "Engineer",
"display_name": "Software Engineer",
"purpose": "Build and maintain the product."
}
}' \
"https://metapulse.com/api/v4/roles?organisation_id=<ORG_ID>"

Returns the created role (HTTP 200):

{
"id": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"name": "Engineer",
"displayName": "Software Engineer",
"purpose": "Build and maintain the product.",
"function": null,
"results": null,
"teamLeader": false,
"assistant": false,
"graphPermissionLevel": "view",
"knowledgeItemId": null,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-01-15T09:14:54.133+10:00"
}

See Errors for the validation failure response.

Body Parameters (under role)

Parameter

Required

Description

name

yes

Internal name (must be unique within the organisation).

display_name

no

Display name shown on the chart.

purpose

no

The role's purpose.

function

no

The role's function.

valuable_final_product

no

The role's valuable final product (also accepted as results).

responsible

no

Boolean — sometimes referred to as team_leader.

team_leader

no

Alias of responsible.

assistant

no

Boolean.

graph_permission_level

no

One of none, view, edit, admin.

knowledge_item_id

no

Knowledge item linked to this role.

Update a Role

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X PATCH \
-d '{ "role": { "display_name": "Staff Software Engineer" } }' \
"https://metapulse.com/api/v4/roles/<ID>?organisation_id=<ORG_ID>"

Accepts the same body parameters as create. Returns the updated role (HTTP 200):

{
"id": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"name": "Engineer",
"displayName": "Staff Software Engineer",
"purpose": "Build and maintain the product.",
"function": "Writes, reviews, and ships code.",
"results": "Working features delivered to customers.",
"teamLeader": false,
"assistant": false,
"graphPermissionLevel": "view",
"knowledgeItemId": null,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-10T14:32:01.554+10:00"
}

See Errors for the validation failure response.

Errors

All endpoints return errors in a consistent shape:

{ "error": { "message": "<human-readable message>" } }

Status

When

400 Bad Request

Validation failure on create/update (e.g. blank or non-unique name).

401 Unauthorized

Missing or invalid api-email / api-key headers, or your user lacks permission for the action.

404 Not Found

The role or organisation id doesn't exist or isn't visible to your user.

Example validation error from create or update:

{ "error": { "message": "Unable to save role due to the following error: Name can't be blank" } }

Positions

The Positions API lets you list, read, create, update, archive, and reassign positions. A position sits on a team, points at a role (see the Roles API), and is filled by a member.

For an introduction to authentication and the common request format, see the MetaPulse API v4 overview.

All examples assume:

  • API_EMAIL — the email of your MetaPulse user

  • API_KEY — the API key from your MetaPulse user profile

  • ORG_ID — your organisation id (e.g. org12abc3de4)

Every endpoint requires the organisation_id query parameter.

Endpoints

Method

Path

Description

GET

/api/v4/positions

List positions

GET

/api/v4/positions/:id

Show a position

POST

/api/v4/positions

Create a position

PATCH

/api/v4/positions/:id

Update a position

POST

/api/v4/positions/:id/replace_member

Reassign the member on a position

POST

/api/v4/positions/:id/archive

Archive a position

The Position Object

{
"id": "pos45fgh6ij7",
"name": "Senior Engineer",
"teamId": "tea12abc3de4",
"roleId": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"roleName": "Engineer",
"memberId": "mem78klm9no0",
"alias": null,
"sourcePositionId": null,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}

Field

Type

Description

id

string

Unique id for the position (e.g. pos45fgh6ij7).

name

string

Display name. Falls back to roleName if no custom name is set.

teamId

string | null

Id of the team this position sits on.

roleId

UUID | null

Id of the role this position represents.

roleName

string | null

Name of the role, denormalised for convenience.

memberId

string | null

Id of the member currently filling this position. null when the position is vacant.

alias

string | null

Alias type when the position is a reference to another position.

sourcePositionId

string | null

When alias is set, the id of the underlying position this aliases.

archivedAt

timestamp | null

Set when the position is archived.

draft

boolean

true if the position is in draft (unpublished) state.

createdAt

timestamp

When the position was created.

updatedAt

timestamp

When the position was last updated.

List Positions

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/positions?organisation_id=<ORG_ID>"

Returns a JSON array of position objects, ordered by sequence then id. Defaults to active (non-archived) positions. Pagination defaults to 50 results per page; pass page and per_page (up to 500) to customise.

Query Parameters

Parameter

Description

team_id

Only return positions on this team.

member_id

Only return positions filled by this member.

role_id

Only return positions for this role (UUID).

archived

true to return only archived positions, all to return both active and archived. Default: active only.

page

Page number (1-based).

per_page

Page size (default 50, max 500).

[
{
"id": "pos45fgh6ij7",
"name": "Senior Engineer",
"teamId": "tea12abc3de4",
"roleId": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"roleName": "Engineer", "memberId": "mem78klm9no0",
"alias": null,
"sourcePositionId": null,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}
]

Show a Position

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X GET \
"https://metapulse.com/api/v4/positions/<ID>?organisation_id=<ORG_ID>"

Returns a single position object, or 404 Not Found if no position with that id exists in the organisation.

{
"id": "pos45fgh6ij7",
"name": "Senior Engineer",
"teamId": "tea12abc3de4",
"roleId": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"roleName": "Engineer",
"memberId": "mem78klm9no0",
"alias": null,
"sourcePositionId": null,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-02T11:02:10.221+10:00"
}

Create a Position

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{
"position": {
"team_id": "tea12abc3de4",
"role_id": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"member_id": "mem78klm9no0",
"custom_name": "Senior Engineer"
}
}' \
"https://metapulse.com/api/v4/positions?organisation_id=<ORG_ID>"

Returns the created position (HTTP 200):

{
"id": "pos45fgh6ij7",
"name": "Senior Engineer",
"teamId": "tea12abc3de4",
"roleId": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"roleName": "Engineer",
"memberId": "mem78klm9no0",
"alias": null,
"sourcePositionId": null,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-01-15T09:14:54.133+10:00"
}

See Errors for the validation failure response.

Body Parameters (under position)

Parameter

Required

Description

team_id

yes

Id of the team this position will sit on.

role_id

no

UUID of the role this position represents.

member_id

no

Id of the member filling this position. Omit for a vacant position.

custom_name

no

Override the role name with a position-specific label.

sequence

no

Sort order among siblings.

temporary

no

Mark as a temporary position.

floor_section, floor_name, building, city, state, country_code, time_zone, custom_location

no

Location fields.

draft

no

Create as a draft (unpublished) position. Create-only; ignored on update.

Update a Position

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X PATCH \
-d '{ "position": { "custom_name": "Staff Engineer" } }' \
"https://metapulse.com/api/v4/positions/<ID>?organisation_id=<ORG_ID>"

Accepts the same body parameters as create, except member_id and draft (which is create-only). To change which member fills a position, use Replace member. If you include member_id in an update request it is silently ignored.

Returns the updated position (HTTP 200):

{
"id": "pos45fgh6ij7",
"name": "Staff Engineer",
"teamId": "tea12abc3de4",
"roleId": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"roleName": "Engineer",
"memberId": "mem78klm9no0",
"alias": null,
"sourcePositionId": null,
"archivedAt": null,
"draft": false,
"createdAt": "2025-01-15T09:14:54.133+10:00",
"updatedAt": "2025-02-10T14:32:01.554+10:00"
}

See Errors for the validation failure response.

Replace a Member

Reassigns the member filling a position. Internally this archives the existing position and returns a fresh one with the new member assigned — so the response id differs from the request id. The original position's id is echoed back as previousPositionId.

curl -i \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{ "member_id": "mem99qrs8tuv" }' \
"https://metapulse.com/api/v4/positions/<ID>/replace_member?organisation_id=<ORG_ID>"

Pass "member_id": null to vacate the position. Returns HTTP 201:

{
"id": "pos11new2222",
"name": "Senior Engineer",
"teamId": "tea12abc3de4",
"roleId": "9c1f4d22-2c8a-4d3e-b5b7-8b6e6a1f1a01",
"roleName": "Engineer",
"memberId": "mem99qrs8tuv",
"previousPositionId": "pos45fgh6ij7",
"archivedAt": null,
"draft": false,
"createdAt": "2025-02-10T09:14:54.133+10:00",
"updatedAt": "2025-02-10T09:14:54.133+10:00"
}

Archive a Position

curl -i \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
"https://metapulse.com/api/v4/positions/<ID>/archive?organisation_id=<ORG_ID>"

Returns HTTP 200 with an empty body. Any aliases of the position are archived along with it.

Errors

All endpoints return errors in a consistent shape:

{ "error": { "message": "<human-readable message>" } }

Status

When

400 Bad Request

Validation failure on create/update (e.g. missing required association).

401 Unauthorized

Missing or invalid api-email / api-key headers, or your user lacks permission for the action.

404 Not Found

The position, team, role, member, or organisation id doesn't exist or isn't visible to your user.

Example validation error from create or update:

{ "error": { "message": "Unable to save position due to the following error: Team can't be blank" } }

Set Custom Attributes for a Position

Using the position ID obtained from the Members List above or via Team Chart Data Export, you can update the position's Custom Attributes as follows:

curl -i \      
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "api-email: <API_EMAIL>" \
-H "api-key: <API_KEY>" \
-X POST \
-d '{"name": "Department", "value": "A17"}' \
"https://metapulse.com/api/v4/posts/<POST_ID>/custom_attributes"

Debugging

_______________________________________

Getting APIs to work can be a real pain sometimes, especially if you don't have direct access to send requests out.

A good tool to figure out if you are sending the API request correctly is beeceptor.com which is a free service to show you what your application is actually sending to MetaPulse.

Debugging

curl -i -H "api-key: API_KEY" \
        -H "api-email: bob@example.com" \
     https://test-metapulse.free.beeceptor.com/authentication

After sending this you'll get something back like:

HTTP/1.1 200 OK
Date: Tue, 05 Feb 2019 12:23:29 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
Vary: Accept-Encoding


Hey ya! Great to see you here. Btw, nothing is configured for this request path. Create a rule and start building a mock API.

Which shows you BeeCeptor got your message.

Going to https://app.beeceptor.com/console/test-metapulse will then show you a request, which you can click and then view the headers of and see something like:

Which looks good!
​ 

Questions / Comments

_______________________________________

If you have any questions or comments, please contact us via support.

Did this answer your question?