Welcome to Planhat's API! It will help you interact with Planhat whenever you need something that is not covered by one of our standard integrations.
The API has a few "open" endpoints that can be used to push data without the need to authenticate. This is ideal if all you need is to send some server side metrics, user activities, call logs, etc. If you need more than that, API keys will give you access to the full API which will let you do almost anything related to your data in Planhat.
The base url for general API requests is:
https://api.planhat.com
The base url for user tracking and metrics is:
https://analytics.planhat.com
Main API Endpoint
Planhat comes with a quota (soft limit) of 200 API calls per minute to our main api. The hard limit is 150 requests per second with bursts of up to 50 parallel requests.
Note: When modifying or creating multiple records in one request (large bulk operations), it is advised to execute the requests sequentially instead of in parallel. This will aid in maintaining data integrity.
For all bulk upsert operations, regardless the model there is an upper limit of 5,000 items per request.
Analytics Endpoint
The user tracking and metrics endpoints at analytics.planhat.com are not affected by these limits and can handle very high volumes of requests.
However, there is a hard limit of 32MB on the body of each post to Planhat, which typically corresponds to about 150,000 items.
In some cases you may prefer to manage your Planhat data in some other way than over api. For those situations you have the following options:
Manually in the app
It's easy to update any data in Planhat manually from within the app. You can create, update and remove whole objects or specific properties, bulk update is typically available as well.
Import / Export
Another option to create and update data in Planhat is via xlsx file import. The file import corresponds to a bulkUpsert operation, creating items where they don't exist and updating if they already exist.
Integrations
Planhat comes with many out of the box integrations to help sync data to and from CRMs such as Salesforce and Hubspot, Support Tools, Jira, NPS tools, etc. For those using Salesforce this is a common way to load companies and contacts (among other things) into Planhat.
Zapier
There's a Zapier app for Planhat supporting the basic events and actions, for example to create companies, endusers and Notes. But using web requests really any api endpoint could be leveraged.
Most end-points require authentication by an API Access Token that can be generated using Service Accounts under the Settings section in Planhat. Once a token is created, it will appear once and last forever. Make sure to copy and store it securely once generated.
To disable a token simply disable the Service Account, pause it, or remove the API Access Token from Service Account, the latter will permanently invalidate the token.
API Access Tokens (API keys) are static tokens that belong to a Service Account, meaning that whatever operation performed with this token, will appear as a Service Account action. It is possible to limit the access scope for an API Access Token by configuring permissions on the Service Account level.
The Token should be placed in the Authorization header in ONE of the following ways:
Authorization: Bearer {{apiAccessToken}}
or
Authorization: Basic [base64encode({{apiAccessToken}}:)]
Please note the colon after your token when using basic authentication.
The Planhat API can respond with 5 possible HTTP codes: 200, 206, 400, 403 and 500.
For all the requests the API will respond with an object or string containing either the created/updated object or information to help you understand a possible error code. This is especially helpful for error codes where more information can help you understand what went wrong with the request.
200: Ok code, this means the operation was successful.
206: Partially Ok code, this means that some operations were successful but there are others with errors.
400: Bad request, this means that you have a problem with the request payload, usually a required key is missing or it's duplicated.
403: Permission error, this means that you don't have the right permissions to execute the operation. Check that your API token has the correct permissions.
500: Server error, this means that there was an error on the Planhat side, try again and if you get the same 500 error please contact support.
We have built these endpoints as “data sinks”. In this context, 200 means that we have successfully received the data for processing.
There are two key reasons we do not process the data in real-time and return a final result:
Firstly, due to the high data volumes and significant processing required for each event (e.g., analytics events need to be linked to the correct company, and an end user may be created and linked automatically in the process).
Secondly, because Metrics data is often sent by our Tracking Script, the request often goes directly from your enduser's browser to our endpoint, meaning there is no value in returning any errors.
In order to keep consistency and make data the most reliable as possible, the API relies on a set of standards and rules to normalize data it takes in.
Some data a client sends can either be invalid or transformed to be accommodated and stored in a better shape.
All time-related data will be stored in UTC (offset 0) and API can tolerate non UTC values when handling Date/Time fields but they'll be represented in UTC time.
Futhermore, we provide three data types to work with dates:
Day,
Date and
Date/Time.
All those types will be explained below.
When a field has day type API expect it to be a number also known as UNIX Epoch, the value of it should be: the amount of days that have passed since Jan 1, 1970. For example, 19508 would represent the date May 31, 2023. This type of data can't tolerate time.
API can receive and handle ISO 8601 strings with or without time and timezone for day fields, although the end result will always be the number of days as explained above.
The following date strings are valid and will be converted correctly to the epoch representation:
Input | Result |
---|---|
2023-05-01T00:00:00.000Z | 19478 |
2023-05-02 | 19479 |
2023-05-03T05:00:00.000+02:00 | 19480 |
Date type fields are stored as ISO 8601 date strings with zeroed time (T00:00.000Z). For example: 2023-05-01T00:00:00.000Z. When a time part is provided for this type of field it will be ignored.
The following date strings are valid and will have time zeroed when it's the case:
Input | Result |
---|---|
2023-05-31T15:21:19.144Z | 2023-05-31T00:00:00.000Z |
2023-05-31T15:21:19.000+02:00 | 2023-05-31T00:00:00.000Z |
2023-05-31 | 2023-05-31T00:00:00.000Z |
Date/Time type fields are stored as ISO 8601 date strings with time in UTC. For example: 2023-05-01T21:53:22.634Z will be saved exactly like that. When timezone is provided we save the UTC representation of it
The following date strings are valid and will have time zeroed when it's the case:
Input | Result |
---|---|
2023-05-31T15:21:19.144Z | 2023-05-31T15:21:19.144Z |
2023-05-31T15:21:19.000+02:00 | 2023-05-31T13:21:19.000Z |
2023-05-31 | 2023-05-31T00:00:00.000Z |
The bulkupsert endpoints accept an array of objects to be upserted (created and/or updated).
To decide if an object will be inserted/created or updated, we first try to match it with exiting records in Planhat.
This matching can be based on a few different keyables (keys used by planhat to identify resources), typically:
_id (planhat native id).
sourceId (id from some external systems e.g. your CRM).
externalId (id in your own system).
The exact keyable available depends on the resource in question and these are listed under each section here in the docs.
If no keyable is provided, or if the provided key doesn't match any existing record a new record will be created, assuming minimum required information is provided.
Generally very few fields are required, for example you are allowed to create a contact without providing first or last name.
The one exception is that most objects must be associated with a company profile in Planhat, which means that you'll need to provide a planhat companyId to create most objects.
To make an update you typically don’t need to provide companyId since the record already exists and is mapped to a company profile.
For an update to make sense it should contain at least one keyable to be used for matching and at least one property to be updated.
Properties that are used as keyable can only be updated by providing a higher priority key.
In general the hierarchy of keyables are: _id > sourceId > externalId.
In cases when the same update has to be applied to multiple documents, it is possible to use reduced payload.
Bulk upserts can respond with 5 possible HTTP codes: 200, 206, 400, 403 and 500.
200: Ok code, this means all the operation (create/update) were successful.
206: Partial content, this means that some operations were successful but there are others with errors. Check the createdErrors/updatedErrors section on the response object for more information.
400: Bad request, this means that you have a problem with the request payload, usually a required key is missing or it's duplicated. Check the createdErrors/updatedErrors section on the response object for more information.
403: Permission error, this means that you don't have the right permissions to execute one or all the operations. Check the permissionErrors section on the response object for more information.
500: Server error, this means that there was an error on the Planhat side, try again and if you get the same 500 error please contact support.
The bulk upsert operation response with an object containing different properties each of which has some valuable information.
{
"created": 0,
"createdErrors": [],
"insertsKeys": [],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [],
"permissionErrors": []
}
created: Number of elements created.
createdErrors Array of error objects specifying the detail why a create intend failed.
insertsKeys Array of objects containing the inserted keys for each created element.
updated Number of elements updated.
updatedErrors Array of error objects specifying the detail why an update intend failed.
updatesKeys Array of objects containing the modified keys for each updated element.
nonupdates Number of element that were not updated.
modified Array of ids of updated elements.
upsertedIds Array of ids of created elements.
permissionErrors Array of objects containing the detail why a create or update intend failed due a permission problem.
[{externalId: '123', firstName: 'luke'}]
This may find a contact with externalId equal to 123 and then set firstName to Luke.
But because externalId is used for matching it will not be updated.
To update externalId in this case you'll need to provide a matching sourceId or planhatId (_id)
[{_id: '507f191e810c19729de860ea', externalId: '999', firstName: 'luke'}]
If this were the same record as above (based on planhatId) then it would update externalId from 123 to 999.
Reduced payload to perform identical updates of multiple documents.
{
"update": {"description": "New name for two companies"},
"key": "_id",
"ids": ["6262adb8b4f420096d599dd3", "6262adb8b4f420096d599db5"]
}
the same, but using sourceId
{
"update": {"custom": {"contract value": 16}},
"key": "sourceId",
"ids": ["srcid-1", "srcid-2"]
}
- Error due a missing required parameter
{
"created": 0,
"createdErrors": [
{
"item": {
"fromDate": "2021-07-28T00:00:00.000Z",
"toDate": "2022-07-28T00:00:00.000Z",
"mrr": 100,
"product": "Large License",
},
"err": [
{
"el": "companyId",
"error": "Required Field"
}
]
}
],
"insertsKeys": [],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [],
"permissionErrors": []
}
- Error due a invalid object ID
{
"created": 0,
"createdErrors": [
{
"data": [
{
"_id": "abcd",
"mrr": 200000
}
],
"err": "Cast to ObjectId failed for value \"abcd\" (type string) at path \"_id\" for model \"License\""
}
],
"insertsKeys": [],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [],
"permissionErrors": []
}
- Error due a invalid type
{
"created": 0,
"createdErrors": [
{
"data": [
{
"_id": "507f191e810c19729de860eb",
"mrr": "1500"
}
],
"err": [
{
"mrr": "test",
"error": "Not valid type"
}
]
}
],
"insertsKeys": [],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [],
"permissionErrors": []
}
Note: For all bulk upsert operations, regardless the model there is an upper limit of 5,000 items per request.
Keeping track of your endusers activity is an important part of the Customer Success effort. Getting started involves only two steps.
Decide a few events (user actions) that you want to track.
Decide how you want to get that information from your users into Planhat.
The most obvious events are probably logins and page-views. Logins tend to be fairly inaccurate since it depends a lot on user behavior, some people login and logout a lot, others keep their sessions open. Page views is likely a better metric. Even though page views have relatively weak correlation with the value created, it does give you a general sense of activity level, and it’s great to understand when a given user/customer was last active.
In addition to page views you can probably find even more meaningful metrics such as "did an advanced search", "created a campaign", "added a team-member" etc. The exact metrics will obviously depend on the service you provide but 2-3 such events should be more than enough to get started. Add a weight if you want to indicate that some actions are more important/valuable than others.
There are 4 different ways of getting your enduser activity into Planhat.
API (real time)
Planhat Tracking Script
Segment
API Bulk
Note: Regardless your location the base URL for User Tracking events is always https://analytics.planhat.com
Your second option is to add a small tracking script to your application. Like most other tracking scripts, it’s a tiny snippet (< 1 kb) that you place just before the Head closing tag on your web app. The snippet will asynchronously load the tracking script to send data directly from your users to Planhat. The tracking script will not slow down your app or have any noticeable impact on your users.
To get your Tenant UUID please visit the Developer section in Planhat App.
<script type="text/javascript"> var plantrack=plantrack||[];!function(){for(var t=["init","identify","track"], a=function(t){ return function(){plantrack.push([t].concat(Array.prototype.slice.call(arguments,0)))}},n=0;n<t.length;n++)plantrack[t[n]]=a(t[n])}(),plantrack.load=function(t,a){plantrack._endpoint=t,a&&plantrack.init(a); var n=document.createElement("script");n.type="text/javascript",n.async=!0, n.src="https://app.planhat.com/analytics/plantrack.min.js"; var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(n,r)}; plantrack.load("https://analytics.planhat.com/analytics/{{tenantUUID}}"); </script>
Then in your application, identify users as they login by calling
plantrack.identify(USER_ID, {EXTRA_INFO}).
USER_ID - corresponds to externalId of the EndUser in Planhat. Note! If users can be identified only by email, in that case simply pass "null" as a first argument to plantrack.identify but make sure to specify the user email property in EXTRA_INFO.
EXTRA_INFO - the way to specify additional information to identify (or create if it's allowed by your settings) a user. Supported fields are: "email", "name", "companyExternalId", "assetExtId", "projectExtId". This information is saved in a cookie ("_plantrack") and used to identify the user in subsequent requests.
plantrack.identify(USER_ID, { email: ojpsoi57pzn@mycompany.com, name: {{userName}}, companyExternalId: "mycompany-ext-id" });
After that, when the event you would like to track happens simply call plantrack.track(ACTION, [EXTRA_INFO]) from your app, for example:
plantrack.track("created a new project", {"weight": 7});
If you want to add more information, do it in a info property inside the JSON object of the second argument of the function call, like this:
plantrack.track("created a new project", {"weight": 7, "info": {"prop": "value", "prop2": "value2"} });
User information stored in the cookie (most importantly USER_ID or email passed in EXTRA_INFO) will automatically be added to all tracking requests.
https://analytics.planhat.com/analytics/{{tenantUUID}}
In table below you can get some of the field description for request.
Property | Required | Type | Description |
---|---|---|---|
name | string | Full name of the contact/user. This property is not required but it's recommended. | |
string | The contact’s email. | ||
externalId | string | The contact’s id (user_id) in your system (required if email not specified). | |
companyExternalId | string | Typically this is the account/customer id in your own system and can be very helpful in mapping new enduser to correct customer profile in Planhat. | |
action | string | Parameter describing the user activity. Typically on the form Action + Object, for example "Sent Invoice", but it could also be just "Login" or something else that describes the activity. | |
assetExtId | string | Asset id in your system that corresponds to externalId of Asset in Planhat. | |
projectExtId | string | Project id in your system that corresponds to externalId of Project in Planhat. | |
info | object | An optional valid JSON object where you can specify additional information related to the event. If the user activity was "purchased a gift card" then it might make sense to add info about the price, or product category. | |
passive | boolean | Pass true to track event as passive which will NOT affect on contact/user Last Seen/Active date, Beat & Experience. Passive events will not show in the Company Profile “Overview” tab under “Recently Active”, but will show in “Recent Activities” both in the Company Profile “Usage” tab and the End User Profile “Overview” tab. | |
weight | number | Optional numeric value lets you indicate that some actions are more important/valuable than others. |
If we receive a call (Identify or Track) for a user that doesn’t yet exist in Planhat, and the request contains a customer id, then Planhat will automatically create a new user for you. This is highly recommended unless you create users in Planhat automatically through the API. If you’re providing an email address it is also likely that Planhat will be able to map a new enduser to the correct customer account with sufficient accuracy to avoid manual confirmation, however most Segment set-ups rely not on email but user id.
When a new end user is auto-created by Planhat, their First & Last names, External ID and Email will all be populated automatically if provided in the call to the analytics endpoint.
If an end user already exists in Planhat, and any of the above properties (First Name, Last Name, External ID, Email) are sent, the End User will only be updated if they do not already have a value for the relevant property. If, however, the end user already has a value, the property will not be updated by the call.
curl --location -g --request POST 'https://analytics.planhat.com/analytics/{{tenantUUID}}' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "ivars@planhat.com",
"action": "Logged in",
"externalId": "ojpsoi57pzn",
"companyExternalId": "Planhat-81ock9l81wl",
"weight": 1,
"info": {
"index": 20,
"theme": "Blue"
}
}'
200 OK
OK
https://analytics.planhat.com/analytics/bulk/{{tenantUUID}}
The count property for User Activities cannot handle a value greater than 300 (0 ≤ count ≤ 300). If a value over 300 is sent in the count property, then the endpoint will receive a count of 1 instead of the value sent.
Property | Required | Type | Description |
---|---|---|---|
name | string | Full name of the contact/user. | |
string | The contact’s email. | ||
euExtId | string | The contact’s id (user_id) in your system (required if email not specified). | |
cId | objectId | Typically the account/customer id in your system, the same id have to be present as externlId in Planhat.This is required to automatically add new endusers to the correct customer profile in Planhat. If left out, a Customer Success Rep will manually have to assign new endusers to the appropriate customer, or Planhat will make a qualified guess when certain enough it will be correct. | |
date | string | Pass a valid ISO date string to specify the date of the event. If none is provided we will use the time the request was received. | |
action | string | Parameter describing the user activity. Typically on the form Action + Object, for example "Sent Invoice", but it could also be just "Login" or something else that describes the activity. This parameter is optional, but highly recommended and required if you want the appear in the event stream. | |
assetExtId | string | Asset id in your system that corresponds to externalId of Asset in Planhat. | |
projectExtId | string | Project id in your system that corresponds to externalId of Project in Planhat. | |
count | integer | Indicate if the event happened multiple times, for example if the import cover past 24 hours and a given user logged in twice during this period, you could send it as one row and instead set the count to 2, of course they'd get the exact same date, but mostly this is not an issue. Defaults to one (1). | |
passive | boolean | Pass true to track event as passive which will NOT affect on contact/user Last Seen/Active date, Beat & Experience. Passive events will not show in the Company Profile “Overview” tab under “Recently Active”, but will show in “Recent Activities” both in the Company Profile “Usage” tab and the End User Profile “Overview” tab. | |
weight | number | Optional numeric value lets you indicate that some actions are more important/valuable than others. |
curl --location -g --request POST 'https://analytics.planhat.com/analytics/bulk/{{tenantUUID}}' \
--header 'Content-Type: application/json' \
--data-raw '[
{
"name": "Ivars Mucenieks",
"email": "ivars@planhat.com",
"cId": "abc123",
"action": "Logged in",
"weight": 1,
"count": 1
},
{
"name": "Ivars Mucenieks",
"email": "ivars@planhat.com",
"cId": "abc123",
"action": "Sent Invoice",
"weight": 1,
"count": 1
}
]'
200 OK
OK
https://analytics.planhat.com/dock/segment
As a third option, Segment can be used to send User Events (user tracking data) to Planhat. When we receive an event from Segment, we use the "user id" and/or email to to know which Planhat user the event refers to. The events are then displayed in Planhat both on user and company level. When presented in text form, we display it as [user name] + [event]. Preferably use event names on the form "verb + noun". For example "downloaded a report" is a better event name then "report_dowloaded".
Notes:
Segment is a service with it’s own license cost.
Segment endpoint uses Basic Auth passing the tenantUUI as username.
If we receive a call (Identify or Track) for a user that doesn’t yet exist in Planhat, and the request contains a customer id, then Planhat will automatically create a new user for you. This is highly recommended unless you create users in Planhat automatically through the API. If you’re providing an email address it is also likely that Planhat will be able to map a new enduser to the correct customer account with sufficient accuracy to avoid manual confirmation, however most Segment set-ups rely not on email but user id.
When a new end user is auto-created by Planhat, their First & Last names, External ID and Email will all be populated automatically if provided in the call to the analytics endpoint.
If an end user already exists in Planhat, and any of the above properties (First Name, Last Name, External ID, Email) are sent, the End User will only be updated if they do not already have a value for the relevant property. If, however, the end user already has a value, the property will not be updated by the call.
Events will be completely ignored when any of the following conditions are met.
Request is not of type "Identify" or "Track" Both User Id and Email are missing
If we receive a call (Identify or Track) for a user that doesn’t yet exist in Planhat, and the request does NOT contain information about which customer it relates to, and we have no other way to relate the user to a customer with reasonable confidence, then it will be discarded but added a report in Planhat to help you identify potential issues with the integration. Typically this may happen when users that loggedin (with a persistent session) before the integration was activated. Events from these users will end up in the log, and eventually as the user gets logged out and login again it’ll start working as expected.
Property | Required | Type | Description |
---|---|---|---|
type | string | Type of segments should be (Identify or Track). | |
traits | object | Object of some data ( email or user id is required) |
curl --location -g --request POST 'https://analytics.planhat.com/dock/segment' \
-u {{tenantUUID}} \
-k \
--header 'Content-Type: application/json' \
--data-raw '{
"type": "identify",
"traits": {
"name": "Ivars Mucenieks",
"email": "ivars@planhat.com",
"companyId": "ABCDE"
}
}'
200 OK
OK
https://analytics.planhat.com/dimensiondata
While User Activity says a lot about user engagement, it doesn't always reflect the value created. Dimension Data is a set of model level metrics (Company by default) to understand how well your customers are doing, and the value they get out of your service.
Depending on what metrics you pick you might either want to send it as it happens or once a day. Number of user logins for example. You could either send a post everytime a user logs in, or you could save logins at your end and send the total count for the day to planhat once a day. Typically the more granular data you send to planhat, the more options you’ll have to crunch that data later.
Note: The end point accepts either a single object or an array, which can be useful if you run a batch update with some interval, or if you initially would like to load historical data.
Note: regardless your location the base URL for User Tracking events is always https://analytics.planhat.com.
In table below you can get some of the field description for request.
Property | Required | Type | Description |
---|---|---|---|
dimensionId | string | Any string without spaces or special characters. If you're sending "Share of Active Users" a good dimensionId might be "activeusershare". It's not displayed in Planhat but will be used when building Health Metrics in Planhat. | |
value | number | The raw (number) value you would like to set. | |
externalId | string | This is the model (company by default) external id in your systems. For this to work the objects in Planhat will need to have this externalId set. | |
model | string | Company (default), EndUser, Asset and Project models are supported | |
date | string | Pass a valid ISO format date string to specify the date of the event. In none is provided we will use the time the request was received. |
https://api.planhat.com/dimensiondata
When fetching dimension data there are some options that can be used via query params:
cId: Id of company.
dimid: Id of the dimension data.
from: Days format interger representing the start day period (Days since January 1, 1970, Unix epoch).
to: Days format interger representing the end day period (Days since January 1, 1970, Unix epoch).
limit: Limit the list length.
offset: Start the list on a specific integer index.
curl --location -g --request GET 'https://api.planhat.com/dimensiondata?cId=611547eebcdda93cc7622958&dimid=testdim&from=18858&to=18880&limit=3' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "611ef080ff18a32f886e40ae",
"dimensionId": "testdim",
"time": "2021-08-20T00:00:00.000Z",
"value": 5,
"model": "Company",
"parentId": "611547eebcdda93cc7622958",
"companyId": "611547eebcdda93cc7622958",
"companyName": "Tenet"
},
{
"_id": "611ef080eb75161dc055880a",
"dimensionId": "testdim",
"time": "2021-08-20T00:00:00.000Z",
"value": 4,
"model": "Company",
"parentId": "611547eebcdda93cc7622958",
"companyId": "611547eebcdda93cc7622958",
"companyName": "Tenet"
},
{
"_id": "611ef080b067346dfd91ad22",
"dimensionId": "testdim",
"time": "2021-08-20T00:00:00.000Z",
"value": 15,
"model": "Company",
"parentId": "611547eebcdda93cc7622958",
"companyId": "611547eebcdda93cc7622958",
"companyName": "Tenet"
}
]
To push dimension data into Planhat is is required to specify the Tenant Token (tenantUUID) in the request URL. This token is a simple uui identifier for your tenant and it can be found in the Developer module under the Tokens section.
curl --location -g --request POST 'https://analytics.planhat.com/dimensiondata/{{tenantUUID}}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"dimensionId": "flightTime",
"value": 1,
"externalId": "airbus",
"model": "Company"
},
{
"dimensionId": "debtRatio",
"value": 5.2,
"externalId": "a320",
"model": "EndUser"
}
]'
200 OK
'{
"processed": 2,
"errors": []
}'
Planhat provides a set of models to which you can interact with via API.
The main properties, options and features are listed below but some models have more properties and functionalities than the ones provided on this documentation. If you don't find something in specific here, please contact support for help.
Standard Arrays in Planhat, such as any System or Custom Multipicklist field on any object, allow for simple Add, Replace and Remove operations as follows:
Add will append the new value(s) to the existing array.
Replace will input the new value(s) instead of the existing array
Remove will remove the new value(s) if present in the existing array
The syntax for applying such array operations is:
{
"property": {
"operation": "insert|replace|remove",
"data": ["value1", "value2", "value3"]
}
};
For example, the following payload would update a custom field called "Industry" by removing the "Healthcare" value:
{
"custom": {
"Industry": {
"operation": "remove",
"data": ["Healthcare"]
}
}
};
https://api.planhat.com/assets
Assets in Planhat can represent many different things depending on your use case. It could be drones, if you're selling a drone tracking product, or it could be instances of your product in cases where a single customer can run multiple instances of your product in parallel. Assets could also represent your different products.
More generally, Assets are "nested objects" for which you may want to track usage separately, but don't need to treat them as separate customers with individual contacts, conversations, etc.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
name | string | Asset name. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
externalId | string | The asset id in your own system. | |
sourceId | string | The asset id from an integration (Sales Force, Hubspot, etc). | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/assets
To create an asset it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/assets' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Asset name",
"companyId": "60df26bfa259250cba9cf816",
"externalId": 1234,
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
}
}'
200 OK
'{
"_id": "60faeda853b8f717ebe36146",
"name": "Asset name",
"companyId": "60df26bfa259250cba9cf816",
"externalId": "1234",
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
},
"companyName": "Test Company"
}'
https://api.planhat.com/assets/:_id
To update an asset it's required to pass the _id in the request URL as a parameter.
Alternately it’s possible to update using the asset externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/assets/extid-{{externalId}}
or
https://api.planhat.com/assets/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/assets/60faeda853b8f717ebe36146' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Asset name 2"
}'
200 OK
'{
"_id": "60ff061d681a6b4da9248694",
"name": "Asset name 2",
"companyId": "60df26bfa259250cba9cf816",
"externalId": "12323",
"companyName": "Test Company"
"__v": 0,
"sourceId": "12323"
}'
https://api.planhat.com/assets/:_id
To get a specific asset it's required to pass the _id in the request URL as a parameter.
Alternately it's possible to get an asset using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/assets/extid-{{externalId}}
or
https://api.planhat.com/assets/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/assets/5ffcce42ad67267f66741147' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "5ffcce42ad67267f66741147",
"companyId": "56bccdf554d64d837d01be9d",
"companyName": "Tenet",
"name": "Gold asset",
"__v": 0,
"custom": {
"Comments": "",
"Main Product": [
"Recipe Database"
],
"Days in Phase": 0,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Overall Outlet Health": 4,
"Kary FF": null
},
"externalId": "4467",
"usage": {
"6053b728fa96fa0262729a3d": 0,
"6053ba62ca3eaf023a54d268": 0
}
}'
https://api.planhat.com/assets
When fetching multiple assets there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/assets?limit=2&offset=0&sort=-name&select=_id,name,companyId' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "60fb0869694ea374023924cb",
"companyId": "56bccdf554d64d837d01be4a",
"name": "ZPA Product"
},
{
"_id": "601c0a253e5ed41388982528",
"companyId": "6011889f52181c5640bf41ba",
"name": "Trello.io"
}
]'
https://api.planhat.com/assets/:_id
To delete an asset it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/assets/60faeda853b8f717ebe36146' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/assets
To create an asset it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update an asset it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple assets with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/assets' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"name": "Asset name",
"companyId": "60df26bfa259250cba9cf816",
"externalId": 1234,
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
}
},
{
"name": "Asset name 2",
"companyId": "60df26bfa259250cba9cf816",
"externalId": 1235,
"sourceId": "sfc-1235",
"custom": {
"field": "custom field"
}
}
]'
200 OK
'{
"created": 2,
"createdErrors": [],
"insertsKeys": [
{
"_id": "60fde9ad57df5b411cf39be5",
"sourceId": "sfc-1234",
"externalId": "1234"
},
{
"_id": "60fde9ad57df5b411cf39be6",
"sourceId": "sfc-1235",
"externalId": "1235"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"60fde9ad57df5b411cf39be5",
"60fde9ad57df5b411cf39be6"
],
"permissionErrors": []
}'
https://api.planhat.com/campaigns
Manage campaigns you are running inside companies, e.g., to drive adoption or to deepen stakeholder relations.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
name | string | Campaign name. | |
campaignPurpose | string | Campaign purpose. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
externalId | string | The campaign id in your own system. | |
sourceId | string | The campaign id from an integration (Sales Force, Hubspot, etc). | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/campaigns
To create an campaign it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/campaigns' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Campaign name",
"campaignPurpose": "Campaign purpose",
"companyId": "60df26bfa259250cba9cf816",
"externalId": 1234,
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
}
}'
200 OK
'{
"_id": "60faeda853b8f717ebe36146",
"name": "Campaign name",
"campaignPurpose": "Campaign purpose",
"companyId": "60df26bfa259250cba9cf816",
"externalId": "1234",
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
},
"companyName": "Test Company"
}'
https://api.planhat.com/campaigns/:_id
To update an campaign it's required to pass the _id in the request URL as a parameter.
Alternately it’s possible to update using the campaign externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/campaigns/extid-{{externalId}}
or
https://api.planhat.com/campaigns/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/campaigns/60faeda853b8f717ebe36146' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Campaign name 2"
}'
200 OK
'{
"_id": "60ff061d681a6b4da9248694",
"name": "Campaign name 2",
"campaignPurpose": "Campaign purpose 2",
"companyId": "60df26bfa259250cba9cf816",
"externalId": "12323",
"companyName": "Test Company"
"__v": 0,
"sourceId": "12323"
}'
https://api.planhat.com/campaigns/:_id
To get a specific campaign it's required to pass the _id in the request URL as a parameter.
Alternately it's possible to get an campaign using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/campaigns/extid-{{externalId}}
or
https://api.planhat.com/campaigns/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/campaigns/5ffcce42ad67267f66741147' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "5ffcce42ad67267f66741147",
"companyId": "56bccdf554d64d837d01be9d",
"companyName": "Tenet",
"name": "Gold campaign",
"campaignPurpose": "Campaign purpose",
"__v": 0,
"custom": {
"Comments": "",
"Main Product": [
"Recipe Database"
],
"Days in Phase": 0,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Overall Outlet Health": 4,
"Kary FF": null
},
"externalId": "4467",
"usage": {
"6053b728fa96fa0262729a3d": 0,
"6053ba62ca3eaf023a54d268": 0
}
}'
https://api.planhat.com/campaigns
When fetching multiple campaigns there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/campaigns?limit=2&offset=0&sort=-name&select=_id,name,campaignPurpose,companyId' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "60fb0869694ea374023924cb",
"companyId": "56bccdf554d64d837d01be4a",
"name": "ZPA Product",
"campaignPurpose": "Campaign purpose"
},
{
"_id": "601c0a253e5ed41388982528",
"companyId": "6011889f52181c5640bf41ba",
"name": "Trello.io",
"campaignPurpose": "Campaign purpose 2",
}
]'
https://api.planhat.com/campaigns/:_id
To delete a campaign it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/campaigns/60faeda853b8f717ebe36146' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/campaigns
To create a campaign it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a campaign it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple campaigns with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/campaigns' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"name": "Campaign name",
"campaignPurpose": "Campaign purpose",
"companyId": "60df26bfa259250cba9cf816",
"externalId": 1234,
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
}
},
{
"name": "Campaign name 2",
"campaignPurpose": "Campaign purpose 2",
"companyId": "60df26bfa259250cba9cf816",
"externalId": 1235,
"sourceId": "sfc-1235",
"custom": {
"field": "custom field"
}
}
]'
200 OK
'{
"created": 2,
"createdErrors": [],
"insertsKeys": [
{
"_id": "60fde9ad57df5b411cf39be5",
"sourceId": "sfc-1234",
"externalId": "1234"
},
{
"_id": "60fde9ad57df5b411cf39be6",
"sourceId": "sfc-1235",
"externalId": "1235"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"60fde9ad57df5b411cf39be5",
"60fde9ad57df5b411cf39be6"
],
"permissionErrors": []
}'
https://api.planhat.com/churn
Each time one of your customers churns or downgrades you can add a specific log about this. Mostly this "churn log" is added manually by the CSM from within Planhat, but there may also be times when you want to add it over API, for example if you're capturing information about downgrades and churn natively in-app in your own platform and want to send that over to Planhat.
The churn logs in Planhat typically contain the reasons for the churn, the value, date etc. It's important to note though that it doesn't affect actual revenue numbers and KPIs such as churn rate, renewal rate etc, on it's own. Those calculations are entirely based on underlying license data.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
companyId | objectId | Related company id (planhat identifier). | |
churnDate | string | ISO date indication when the churn takes effect. | |
currency | string | The currency code, for example "USD". | |
value | number | Monthly churn value. | |
arr | number | Annual churn value. | |
reasons | array | String array with name of the churn reasons to log this churn with that certain reason. | |
comment | string | Comments or description for the churn. | |
snoozed | boolean | Field only used by the systeam. (Autogenerated). | |
products | array | Array of product objects. (Autogenerated). | |
companyName | string | Company name. (Autogenerated). | |
sourceId | string | The churn id from an integration (Sales Force, Hubspot, etc). | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/churn
To create a churn the only real value that is required is the companyId but it doesn't make much sense to have a churn just with a companyId, that is why we suggest specify also a value.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/churn' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"churnDate": "2021-07-28",
"reasons": [
"Change in leadership",
"Budget cuts"
],
"value": 2000,
"currency": "USD",
"comment": "This account could return in the future",
"companyId": "61006bc89a3e0b702ed8ea49"
}'
200 OK
'{
"snoozed": false,
"products": [],
"reasons": [
"Change in leadership",
"Budget cuts"
],
"_id": "6101d1f072c0e0884d5e8f57",
"churnDate": "2021-07-28T00:00:00.000Z",
"value": 2000,
"currency": "USD",
"comment": "This account could return in the future",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Tenet",
"__v": 0
}'
https://api.planhat.com/churn/:_id
To update a churn it's required to pass the _id in the request URL as a parameter.
curl --location -g --request PUT 'https://api.planhat.com/churn/6101d1f072c0e0884d5e8f57' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"value": 25000
}'
200 OK
'{
"_id": "6101d1f072c0e0884d5e8f57",
"snoozed": false,
"products": [],
"reasons": [
"Change in leadership",
"Budget cuts"
],
"churnDate": "2021-07-28T00:00:00.000Z",
"value": 25000,
"currency": "USD",
"comment": "This account could return in the future",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Tenet",
"__v": 0
}'
https://api.planhat.com/churn/:_id
To get a specific churn it's required to pass the _id in the request URL as a parameter.
curl --location -g --request GET 'https://api.planhat.com/churn/58cc4b769649cb337f9d59a9' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "58cc4b769649cb337f9d59a9",
"licenseId": "56bccdf554d64d837d01be5b",
"reasons": [
"Missing features"
],
"comment": "",
"replacement": "",
"companyId": "56bccdf554d64d837d01be59",
"__v": 0,
"companyName": "t2",
"churnDate": "2017-07-29T00:07:49.000Z",
"products": [
"License Fee"
],
"currency": "USD",
"value": 3979.1666666666665,
"custom": null
}'
https://api.planhat.com/churn
When fetching multiple churn there are some options that can be used via query params:
List of churn with downgrades: /churn?downgrades=only
List of churn without downgrades: /churn?downgrades=excluded
List of churn by time range: /churn?from=2020-01-01&to=2020-01-10
(Dates in ISO format).
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/churn' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "583b8d15f075d7b52cd392e2",
"licenseId": "56bccdf654d64d837d01d812",
"reasons": [
"Customer got acquired"
],
"comment": "notes..",
"replacement": "",
"companyId": "56bccdf554d64d837d01be6f",
"__v": 0,
"companyName": "CBS",
"churnDate": "2020-10-10T00:00:00.000Z",
"products": [
"License Fee"
],
"currency": "USD",
"value": 5000,
"custom": null,
"lastUpdated": "2020-10-08T15:09:29.982Z"
},
{
"_id": "58cc4b769649cb337f9d59a9",
"licenseId": "56bccdf554d64d837d01be5b",
"reasons": [
"Missing features"
],
"comment": "",
"replacement": "",
"companyId": "56bccdf554d64d837d01be59",
"__v": 0,
"companyName": "t2",
"churnDate": "2017-07-29T00:07:49.000Z",
"products": [
"License Fee"
],
"currency": "USD",
"value": 3979.1666666666665,
"custom": null
},
]'
https://api.planhat.com/churn/:_id
To delete a churn it's required to pass _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/churn/6101d1f072c0e0884d5e8f57' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/churn
To create a churn it's required define a companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a churn it is required to specify in the payload the _id.
Since this is a bulk upsert operation it's possible create and/or update multiple projects with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/churn' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"churnDate": "2021-07-29",
"reasons": [
"Change in leadership",
"Budget cuts"
],
"value": 2500,
"currency": "USD",
"comment": "This account could return in the future",
"companyId": "61006bc89a3e0b702ed8ea49"
},
{
"_id": "60e5d4dabe45b22e8e97940c",
"comment": "New communication with the CEO, the could return next year"
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "6101d5dc72c0e0884d5e9002"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"6101d5dc72c0e0884d5e9002"
],
"permissionErrors": []
}'
https://api.planhat.com/companies
Companies ("accounts"), are your customers. Depending on your business these might be agencies, schools, other businesses or something else. Companies can also be your previous customers and potentially future customers (prospects).
The company object is one of the most central in Planhat since most other objects relate to it, and it's frequently used to filter out other information, such as endsuers, licenses, notes etc.
In Planhat it is possible have a hierarchical structure for the companies, meaning that they can be grouped into organizations with parents and children in a tree like structure.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
name | string | Name of the company. | |
owner | objectId | The the planhat user id of the Account Manager / Success Manager to whom this company belongs. See the User model section below for info about how to get the user ids. | |
coOwner | objectId | A potential co-pilot, in case a single owner isn’t enough. See the User model section below for info about how to get the user ids. | |
externalId | string | The company id in your own system (will help us match other data you send over such as user activities, custom metrics etc). Not strictly required but if you’ve read this far it’s most likely something you need. | |
sourceId | string | The company id from an integration (Sales Force, Hubspot, etc). | |
phase | string | Each company can be assigned a lifecycle phase in Planhat. It’s a text string that should match the name of one of the phases in Planhat. If the name doesn’t match any of the phases in Planhat it will still be saved. (Autogenerated). | |
status | string | Status of company should be one of the list (prospect,coming,customer,canceled,lost). (Autogenerated). | |
domains | array | Array of strings of company domains based on endusers emails domains. (Autogenerated). | |
h | integer | Health number. (Autogenerated). | |
hProfile | objectId | ObjectId of the current health profile. (Autogenerated). | |
csmScore | integer | CSM Score from 1 to 5. (Autogenerated). | |
mr | number | Current MRR plus the sum of NRR over the past 30 days. (Autogenerated). | |
nrr30 | number | NRR (Sale) value Last 30. (Autogenerated). | |
mrrTotal | number | Accumulated MRR. (Autogenerated). | |
nrrTotal | number | Accumulated non-recurring revenue. (Autogenerated). | |
mrTotal | number | Accumulated Revenue (mrrTotal + nrrTotal). (Autogenerated). | |
description | string | Company description. | |
address | string | Company physical address. | |
country | string | Company country. | |
city | string | Company city. | |
zip | string | Company postal code. | |
phonePrimary | string | Company primary phone number. | |
web | string | Company web site url. | |
customerFrom | string | Start date of the active license. (Autogenerated). | |
customerTo | string | Renewal date of the active license. (Autogenerated). | |
alerts | array | Array of alerts notifications. (Autogenerated). | |
tags | array | Array of tags. | |
products | array | Array of string containing the products. (Autogenerated). | |
licenses | array | Array of objects containing the licenses. (Autogenerated). | |
sales | array | Array of objects containing the sales. (Autogenerated). | |
createDate | string | Creation date. (Autogenerated). | |
lastUpdated | string | Last update date. (Autogenerated). | |
lastRenewal | string | Last renewal date. (Autogenerated). | |
renewalDaysFromNow | number | Number of days before the renewal. (Autogenerated). | |
lastActive | string | Last active date. (Autogenerated). | |
followers | array | Array of followers (users) ids. | |
usage | map | Object containing the usage data. (Autogenerated). | |
lastTouch | string | Last touch date. (Autogenerated). | |
lastTouchType | string | Last touch type. (Autogenerated). | |
lastTouchByType | object | Object containing the info of the last contact. (Autogenerated). | |
nextTouch | string | Date for the next schedule touch. (Autogenerated). | |
phaseSince | string | Date since the last phase change. (Autogenerated). | |
csmScoreLog | array | Array of object containing the csm change log. (Autogenerated). | |
features | array | Array of object containing success units. (Autogenerated). | |
sunits | map | Map object containing success units. (Autogenerated). | |
shareable | object | Object containing the sharable information. (Autogenerated). | |
lastActivities | array | Array of object containing the last activities. (Autogenerated). | |
documents | array | Array of object the uploaded documents. (Autogenerated). | |
orgRootId | objectId | Planhat ID of the top company on the organization tree. All its children must refer to the same root ID.(Autogenerated). | |
orgPath | string | String containing chain of objectIds joined by commas. These describe a hierarchical order of companies within the organization. The leftmost is the parent of the organization, and the last one is the direct parent of the current company. (Autogenerated). | |
mrr | number | Monthly company value. (Autogenerated). | |
arr | number | Annual company value. (Autogenerated). | |
orgMrr | number | MRR of the group. (Autogenerated). | |
orgArr | number | ARR of the group. (Autogenerated). | |
renewalMrr | number | Renewal monthly value. (Autogenerated). | |
renewalArr | number | Renewal annual value. (Autogenerated). | |
orgMrrTotal | number | Total Group MRR. (Autogenerated). | |
orgArrTotal | number | Total Group ARR. (Autogenerated). | |
orgHealthTotal | number | Total group health. (Autogenerated). | |
orgLevel | number | Level of the current company inside the organization. (Autogenerated). | |
orgUnits | number | Number of child companies. (Autogenerated). | |
custom | object | A flexible object with custom data. |
https://api.planhat.com/companies
To create a company it's required define a name.
curl --location -g --request POST 'https://api.planhat.com/companies' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"status": "prospect",
"name": "Tenet",
"externalId": "Planhat-81ock9l81wl",
"phase": "Renewal",
"domains": [
"abcdinc.com",
"777.com"
],
"h": 10,
"csmScore": 4,
"mr": 0,
"nrr30": 0,
"custom": {
"CompanyTeamMembers": [
"564b063a508f068051ee82a5",
"56d5dd4e8422dc141913d0ab"
],
"CompanyTeamMember": "564b063a508f068051ee82a5",
"CompanyMultiList": [
"Test2",
"Test3"
],
"CompanyList": "Test2",
"CompanyDate": "2020-05-08T21:00:00.000Z",
"CompanyDay": 18395,
"CompanyBoolean": true,
"CompanyNumber": 33,
"CompanyRating": 4,
"CompanyRichText": "sfsdfsdfs
aSADS
SADas
",
"CompanyText": "Test"
},
"mrrTotal": 0,
"nrrTotal": 5555,
"mrTotal": 5555,
"country": "Latvia",
"description": "Up and coming tech company
"
}'
200 OK
'{
"_id": "60ff42f8d627295c259999af",
"shareable": {
"team": {
"fields": []
},
"enabled": false,
"euIds": [],
"sunits": false
},
"followers": [],
"domains": [
"abcdinc.com",
"777.com"
],
"collaborators": [],
"products": [],
"tags": [],
"lastPerformedTriggers": [],
"status": "prospect",
"name": "Test Company",
"externalId": "Planhat-81ock9l81wl",
"phase": "Renewal",
"h": 10,
"csmScore": 4,
"mr": 0,
"nrr30": 0,
"custom": {
"CompanyRating": 4,
"CompanyRichText": "Test
rich
text
",
"CompanyText": "Test"
},
"mrrTotal": 0,
"nrrTotal": 5555,
"mrTotal": 5555,
"country": "Latvia",
"description": "Up and coming tech company
",
"csmScoreLog": [
{
"date": "2021-07-26T23:19:20.871Z",
"score": 4
}
],
"phaseSince": "2021-07-26T23:19:20.873Z",
"createDate": "2021-07-26T23:19:20.873Z",
"lastUpdated": "2021-07-26T23:19:20.877Z",
"lastTouchByType": {},
"sales": [],
"licenses": [],
"features": {},
"usage": {},
"documents": [],
"links": [],
"alerts": [],
"lastActivities": [],
"updatedAt": "2021-07-26T23:19:20.880Z",
"__v": 0
}'
https://api.planhat.com/companies/:_id
To update a company it's required to pass the company _id in the request URL as a parameter.
Alternately it’s possible to update using the company externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/companies/extid-{{externalId}}
or
https://api.planhat.com/companies/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/companies/60ff42f8d627295c259999af' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Company new name"
}'
200 OK
'{
"_id": "60ff42f8d627295c259999af",
"shareable": {
"team": {
"fields": []
},
"enabled": false,
"euIds": [],
"sunits": false
},
"followers": [],
"domains": [
"abcdinc.com",
"777.com"
],
"collaborators": [],
"products": [],
"tags": [],
"lastPerformedTriggers": [],
"status": "prospect",
"name": "Company new name",
"externalId": "Planhat-81ock9l81wl",
"phase": "Renewal",
"h": 10,
"csmScore": 4,
"mr": 0,
"nrr30": 0,
"custom": {
"CompanyRating": 4,
"CompanyRichText": "Test
rich
text
",
"CompanyText": "Test",
},
"mrrTotal": 0,
"nrrTotal": 5555,
"mrTotal": 5555,
"country": "Latvia",
"description": "Up and coming tech company
",
"csmScoreLog": [
{
"date": "2021-07-26T23:19:20.871Z",
"score": 4
}
],
"phaseSince": "2021-07-26T23:19:20.873Z",
"createDate": "2021-07-26T23:19:20.873Z",
"lastUpdated": "2021-07-26T23:24:47.778Z",
"lastTouchByType": {},
"sales": [],
"licenses": [],
"features": {},
"usage": {},
"documents": [],
"links": [],
"alerts": [],
"updatedAt": "2021-07-26T23:24:47.778Z",
"__v": 0
}'
https://api.planhat.com/companies/:_id
To get a specific company it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a company using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/companies/extid-{{externalId}}
or
https://api.planhat.com/companies/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/companies/61006bc89a3e0b702ed8ea49' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "61006bc89a3e0b702ed8ea49",
"shareable": {
"team": {
"fields": []
},
"enabled": false,
"euIds": [],
"sunits": false
},
"followers": [],
"domains": [
"stjohns.k12.fl.us"
],
"collaborators": [],
"products": [],
"tags": [],
"lastPerformedTriggers": [],
"owner": "60ccb1c5965cc9e0f3848075",
"custom": {
"Days in Phase": 0,
"Days until renewal": 364,
"# Overdue Invoices": 1,
},
"name": "Tenet",
"phase": "Onboarding",
"status": "prospect",
"phaseSince": "2021-07-27T20:25:44.430Z",
"sunits": {
"5b49b52a1ac87812818de26d": {
"status": "on",
"default": true
}
},
"createDate": "2021-07-27T20:25:44.430Z",
"lastUpdated": "2021-08-11T16:12:41.657Z",
"lastTouchByType": {
"note": "2021-08-22T16:15:50.772Z"
},
"sales": [
{
"_id": "61016c80675c1b871faf2d4f",
"value": 10000,
"product": "Advanced Onboarding",
"_currency": {
"_id": "USD",
"rate": 1,
"symbol": "$",
"isBase": true,
"__v": 0,
"overrides": {}
},
"salesDate": "2021-07-28T00:00:00.000Z",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Tenet",
"__v": 0,
"externalId": "sale-1234"
}
],
"licenses": [],
"features": {},
"usage": {},
"csmScoreLog": [],
"documents": [],
"links": [],
"alerts": [],
"lastActivities": [],
"updatedAt": "2021-08-09T16:54:17.298Z",
"__v": 0,
"h": 3,
"autoRenews": false,
"customerTo": "2022-07-27T00:00:00.000Z",
"headId": "6100772b919fd37905810fc6",
"lastRenewal": "2021-07-27T00:00:00.000Z",
"mr": 15000,
"mrTotal": 15000,
"mrr": 0,
"mrrTotal": 0,
"nrr30": 15000,
"nrrTotal": 15000,
"renewalDate": "2022-07-27T00:00:00.000Z",
"renewalDaysFromNow": 363,
"renewalMrr": 0,
"nps": 8.5,
"sourceId": "119",
"hDiff": -2,
"hDiffDate": "2021-08-04T20:21:24.117Z",
"hProfile": "5f87f152f5fc6f26057ac901",
"orgCount": 0,
"orgPathCount": 0
}'
https://api.planhat.com/companies
When fetching multiple companies there are some options that can be used via query params:
companyId: Filter using company id. Multiple ids can be used separating them by commas.
limit: Limit the list length. Default as 100, max. 5000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/companies?limit=2&offset=0&sort=name' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "61002458cb43626b3a7fb186",
"shareable": {
"team": {
"fields": []
},
"enabled": false,
"euIds": [],
"sunits": false
},
"domains": [
"https://google.lv",
"https://draugiem.lv"
],
"tags": [
"test",
"test2"
],
"owner": null,
"coOwner": null,
"externalId": "23z887cpocs",
"sourceId": "23z887cpocs",
"phase": "Onboarding",
"status": "prospect",
"h": 3,
"csmScore": 3,
"mr": 2,
"nrr30": 3,
"mrrTotal": 4,
"mrTotal": 5,
"name": "Altus",
"phaseSince": "2021-07-27T15:20:56.552Z",
"features": {},
"usage": {},
"alerts": [],
"custom": {
"Days in Phase": 0,
"MRR_PLUS_TWOkwu7xl5ziq": 6
}
},
{
"_id": "6100186428706a6646358453",
"shareable": {
"team": {
"fields": []
},
"enabled": false,
"euIds": [],
"sunits": false
},
"domains": [
"https://google.lv",
"https://draugiem.lv"
],
"tags": [
"test",
"test2"
],
"owner": null,
"coOwner": null,
"externalId": "3mfo0a71pa7",
"sourceId": "3mfo0a71pa7",
"phase": "Onboarding",
"status": "prospect",
"h": 3,
"csmScore": 3,
"mr": 2,
"nrr30": 3,
"mrrTotal": 4,
"mrTotal": 5,
"name": "Beta",
"phaseSince": "2021-07-27T14:29:56.119Z",
"features": {},
"usage": {},
"alerts": [],
"custom": {
"Days in Phase": 0,
"MRR_PLUS_TWOkwu7xl5ziq": 6
}
}
]'
https://api.planhat.com/leancompanies
When you need a lightweight list of all companies in Planhat to match against your own ids etc.
For each company profile in Planhat you'll get back the Planhat Id, External Id, Source ID (eg Salesforce) as well as the name.When fetching lean companies there are some options that can be used via query params:
externalId: Compay externalId.
sourceId: Company sourceId.
status: Company status, e.g. "lost", "prospect".
curl --location -g --request GET 'https://api.planhat.com/leancompanies?status=prospect,lost' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "56bccdf554d64d837d01be8c",
"name": "Chevron",
"externalId": "chevron",
"sourceId": "0012000001UchdsAAB"
},
{
"_id": "56ccc2d39b760ff232295798",
"sourceId": "0012000001Tjy5xAAB",
"name": "United Oil & Gas, Singapore",
"externalId": "CD355120-B"
},
{
"_id": "56bccdf554d64d837d01be63",
"name": "Burger King",
"externalId": "",
"sourceId": "0012000001VKEiVAAX"
},
{
"_id": "56bccdf554d64d837d01be4e",
"name": "McDonalds",
"externalId": "mcdonalds",
"sourceId": "0012000001TwtO7AAJ"
}
]'
https://api.planhat.com/companies/:_id
To delete a company it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/companies/60ff42f8d627295c259999af' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/companies
To create a company it's required define a name.
To update an company it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple companies with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/companies' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"name": "Skynet",
"externalId": 1234,
"custom": {
"field": "custom field"
}
},
{
"name": "Tenet",
"sourceId": "sfc-1235",
"custom": {
"field": "custom field"
}
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"updatedErrors": [],
"insertsKeys": [
{
"_id": "6100512d9a3e0b702ed8e9c8",
"sourceId": "sfc-1235"
}
],
"updated": 1,
"updatedErrors": [],
"updatesKeys": [
{
"_id": "6011889f52181c5640bf41bb",
"sourceId": "0012000001U28SYAAZ",
"externalId": "1234"
}
],
"nonupdates": 0,
"modified": [
"6011889f52181c5640bf41bb"
],
"upsertedIds": [
"6100512d9a3e0b702ed8e9c8"
],
"permissionErrors": []
}'
https://api.planhat.com/conversations
Conversations can be of different types such as email, chat, support tickets and manually logged notes. You can also create your own types in Planhat to represent things such as "in person meeting", "Training" etc. The default types (email, chat, ticket, call) are reserved and should not be created over API.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
subject | string | Title of the conversation. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
description | string | Description of the conversation. | |
snippet | string | Formatted content of the conversation. | |
date | string | ISO date when conversation was created. | |
outDate | string | ISO date when conversation was sent. | |
createDate | string | ISO date when conversation was created. (Autogenerated). | |
type | string | Type of conversation. Must reference a pre-existent conversation type in Planhat, or it will default to type: note. | |
users | array | Array of user objects. | |
endusers | array | Array of involved contacts (endusers ids). (Autogenerated). | |
externalId | string | The asset id in your own system. | |
activityTags | array | Array of string to tag your notes. | |
starred | boolean | Flag to mark a conversation as important or relevant. | |
pinned | boolean | Pin a conversation at the top of the company and/or user profile. | |
emailTemplateIds | array | Array of email templates ids. (Autogenerated). | |
isOpen | boolean | Set a conversation or ticket as open or not, mostly related to CRM integrations (Autogenerated). | |
tags | array | Array of string to tags for the conversation. (Autogenerated). | |
waitsToBeFiltered | boolean | Internal system field. (Autogenerated). | |
timeBucket | array | Internal system field. (Autogenerated). | |
archived | boolean | Mark a conversation as archived. | |
numberOfParts | integer | Internal system field. (Autogenerated). | |
sender | array | Array of objects the sender information. (Autogenerated). | |
history | array | Internal system field. (Autogenerated). | |
userIds | array | Array of user ids involved in the conversation. (Autogenerated). | |
hasMore | boolean | Internal system field. (Autogenerated). | |
isCustomType | boolean | Mark the conversation as custom type or not. (Autogenerated). | |
assigneeName | string | Internal system field. (Autogenerated). | |
numberOfRelevantParts | integer | Internal system field. (Autogenerated). | |
hasAttachments | boolean | Set to true if the conversation has attachments. (Autogenerated). | |
isSeen | boolean | Set to true to flag the conversation as seen. (Autogenerated). | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/conversations
To create a conversation, it is required to define a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/conversations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"users": [
{
"id": "58e231b14246fc73139f29e8"
}
],
"date": "2021-07-29T15:29:34.330Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "New conversation",
"description": "Little call with the client.",
"endusers": [
{
"id": "610091916d643a7c418aef42"
}
],
"activityTags": [],
"useSubject": true,
"ownerId": "58e231b14246fc73139f29e8"
}'
200 OK
'{
"starred": false,
"pinned": false,
"autoTags": [],
"activityTags": [],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"timeBucket": [],
"archived": false,
"_id": "6102e3b08084189dcbf0e3f0",
"users": [
{
"id": "58e231b14246fc73139f29e8",
"name": "Alex",
"isOwner": true
}
],
"date": "2021-07-29T15:29:34.330Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "New conversation",
"description": "Little call with the client.",
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Lara Croft"
}
],
"snippet": "Little call with the client.",
"companyName": "Tenet",
"createDate": "2021-07-29T17:21:52.347Z",
"sender": [],
"history": [],
"__v": 0,
"owner": "60ccb1c5965cc9e0f3848075",
"followers": [],
"userId": "610015551b990c65d4fb0a4c",
"note": "New conversation: Little call with the client.",
"nickName": "Test user"
}'
https://api.planhat.com/conversations/:_id
To update an conversation it's required to pass the _id in the request URL as a parameter.
curl --location -g --request PUT 'https://api.planhat.com/conversations/6102e3b08084189dcbf0e3f0' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"subject": "Chat with the client",
"description": "Slack chat with the client.
"
}'
200 OK
'{
"_id": "6102e3b08084189dcbf0e3f0",
"starred": false,
"pinned": false,
"autoTags": [],
"activityTags": [],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"timeBucket": [],
"archived": false,
"users": [
{
"id": "58e231b14246fc73139f29e8",
"name": "Alex",
"isOwner": true
}
],
"date": "2021-07-29T15:29:34.330Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "Chat with the client",
"description": "Slack chat with the client.",
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Lara Croft"
}
],
"snippet": "Slack chat with the client.",
"companyName": "Tenet",
"createDate": "2021-07-29T17:21:52.347Z",
"sender": [],
"history": [],
"__v": 0
}'
https://api.planhat.com/conversations/:_id
To get a specific conversation it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a conversation using its externalId adding a prefix and passing this keyable as identifiers.
Example:
https://api.planhat.com/conversations/extid-{{externalId}}
curl --location -g --request GET 'https://api.planhat.com/conversations/58e57392c9437d10624593fd' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "58e57392c9437d10624593fd",
"type": "email",
"numberOfParts": 1,
"hasAttachments": false,
"source": "bcc",
"subject": "Test 6 on Oct 21 from BCC",
"snippet": "Two new and one existing endusers! ",
"days": 17095,
"companyId": "56e911619f2ff04215515515",
"timeBucket": [
"2016",
"2016-Q4",
"2016-10",
"2016-W43"
],
"history": [],
"tags": [],
"isOpen": false,
"users": [
{
"id": "57225af2dfb33aa3022e88e9",
"name": "Vargha",
"isOwner": true
}
],
"endusers": [
{
"id": "5b47a07ff1846fd087ede384",
"name": "Max Payne"
}
],
"date": "2016-10-21T15:24:05.000Z",
"__v": 0,
"companyName": "Bonnier",
"createDate": "2016-10-21T15:24:05.000Z",
"outDate": "2016-10-21T15:24:05.000Z",
"numberOfRelevantParts": 1,
"custom": {
"Test FF field to check @today cron job": false,
"t1": 0,
"HScore": 0,
"Days in Phase": 0,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
},
"userIds": [
"57225af2dfb33aa3022e88e9"
],
"hasMore": true,
"isCustomType": false,
"assigneeName": "",
"isSeen": false,
"starred": false,
"pinned": false,
"archived": false
}'
https://api.planhat.com/conversations
When fetching multiple conversations there are some options that can be used via query params:
companyId: Filter using company id. Multiple ids can be used separating them by commas.
limit: Limit the list length. Default as 30, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/conversations?limit=2&offset=0' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"date": "2021-07-29T15:29:34.330Z",
"userIds": [
"58e231b14246fc73139f29e8"
],
"hasMore": false,
"isCustomType": false,
"subject": "Chat with the client",
"snippet": "Slack chat with the client.",
"_id": "6102e3b08084189dcbf0e3f0",
"type": "note",
"tags": [],
"createDate": "2021-07-29T17:21:52.347Z",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Leo company",
"users": [
{
"id": "58e231b14246fc73139f29e8",
"name": "Alex",
"isOwner": true
}
],
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Lara Croft"
}
],
"assigneeName": "",
"activityTags": [],
"hasAttachments": false,
"isSeen": false,
"starred": false,
"pinned": false,
"archived": false
},
{
"date": "2021-07-26T16:51:44.146Z",
"userIds": [
"5f16fd8eee876638a9f2483c"
],
"isCustomType": false,
"subject": "t6",
"_id": "60fee824a4c764252c877c2b",
"type": "note",
"tags": [],
"createDate": "2021-07-26T16:51:48.720Z",
"companyId": "584d9d5505ba1b622f04adb3",
"companyName": "Daimler North America",
"users": [
{
"id": "5f16fd8eee876638a9f2483c",
"name": "Ernesto",
"isOwner": true
}
],
"endusers": [],
"assigneeName": "",
"activityTags": [],
"hasAttachments": false,
"isSeen": false,
"starred": false,
"pinned": false,
"archived": false,
"custom": {
"Activity Count": 0,
"Days in Phase": 0,
"Logins": 0
}
}
]'
https://api.planhat.com/conversations/:_id
To delete an conversation it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/conversations/6102e3b08084189dcbf0e3f0' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"starred": false,
"pinned": false,
"autoTags": [],
"activityTags": [],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"timeBucket": [],
"archived": false,
"_id": "6102e3b08084189dcbf0e3f0",
"users": [
{
"id": "58e231b14246fc73139f29e8",
"name": "Alex",
"isOwner": true
}
],
"date": "2021-07-29T15:29:34.330Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "Chat with the client",
"description": "Slack chat with the client.
",
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Lara Croft"
}
],
"snippet": "Slack chat with the client.",
"companyName": "Leo company",
"createDate": "2021-07-29T17:21:52.347Z",
"sender": [],
"history": [],
"__v": 0
}'
https://api.planhat.com/conversations
To create a conversation it's required define a companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a conversation it is required to specify in the payload the _id.
Since this is a bulk upsert operation it's possible create and/or update multiple projects with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/conversations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"users": [
{
"id": "58e231b14246fc73139f29e8"
}
],
"date": "2021-07-29T15:29:34.330Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "New conversation",
"description": "Little call with the client.",
"endusers": [
{
"id": "610091916d643a7c418aef42"
}
],
"activityTags": [],
"useSubject": true,
"ownerId": "58e231b14246fc73139f29e8"
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "61672167d4ac8780f8f680af"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"61672167d4ac8780f8f680af"
],
"permissionErrors": []
}'
https://api.planhat.com/customfields
Most objects in Planaht can be customized by creating your own custom fields. Which model a given custom fields belongs is indicated by the parent property.
Typically you would create the custom fields from within the Planhat app. But in some special cases you may find it more convenient to manage over API instead.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
name | string | Name of the custom field. | |
type | string | Type of the custom field, it should be one of: number, text, rich text, checkbox, day, date, list, multipicklist, team member, team members, rating, phone, email, enduser, endusers, url. | |
parent | string | Parent phModel. | |
isFeatured | boolean | If true the custom field will appear in the parent's detail view, Default as false. | |
isHidden | boolean | If true the custom field will not appear in any parent's view, Default as false. | |
isShared | boolean | If true the custom field will be shareable on portal, Default as false. | |
isLocked | boolean | If true the custom field will not be editable on the UI, Default as false. | |
isMandatory | boolean | If true the custom field will required to create the parent's model, Default as false. | |
isFormula | boolean | True if the custom field is a formula field. Default as false. | |
treatUndefinedAsZero | boolean | If the custom field is a formula field, this will determine if a formula result null/undefined is replaced by zero. This is useful for custom fields type number. | |
formula | string | Formula definition. | |
listValues | array | Array of options for list and multipick custom types. | |
filter | array | Array of parts (objects) of the filter. (Autogenerated). | |
formulaRefs | array | Array of strings of the formula field references. (Autogenerated). | |
numberFormat | string | Custom number format, this is only valid for number types. |
https://api.planhat.com/customfields
To create an custom field it's required define a name, parent and a type.
curl --location -g --request POST 'https://api.planhat.com/customfields' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"parent": "company",
"type": "number",
"isFeatured": true,
"isHidden": false,
"name": "Number field",
"isFormula": false,
"isLocked": false
}'
200 OK
'{
"isFeatured": true,
"isShared": false,
"listValues": [],
"filter": [],
"formulaRefs": [],
"isFormula": false,
"_id": "61043ced0b92efb8a6339cd1",
"parent": "company",
"type": "number",
"isHidden": false,
"name": "Number field",
"isLocked": false,
"__v": 0
}'
https://api.planhat.com/customfields/:_id
To update an custom field it's required to pass _id in the request URL as a parameter.
curl --location -g --request PUT 'https://api.planhat.com/customfields/61043ced0b92efb8a6339cd1' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"isFeatured": false,
"isHidden": true
}'
200 OK
'{
"_id": "61043ced0b92efb8a6339cd1",
"isFeatured": false,
"isShared": false,
"listValues": [],
"filter": [],
"formulaRefs": [],
"isFormula": false,
"parent": "company",
"type": "number",
"isHidden": true,
"name": "Number field",
"isLocked": false,
"__v": 0
}'
https://api.planhat.com/customfields/:_id
To get a specific custom field it's required to pass the _id in the request URL as a parameter.
curl --location -g --request GET 'https://api.planhat.com/customfields/5c94de4752e54d5ce538ae18' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "5c94de4752e54d5ce538ae18",
"isFeatured": true,
"listValues": [],
"parent": "invoice",
"type": "text",
"isHidden": false,
"name": "PO Number"
}'
https://api.planhat.com/customfields
When fetching multiple custom fields there are some options that can be used via query params:
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/customfields?limit=2&offset=0' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "5c8a24fdc923c77bf64dc567",
"isFeatured": false,
"listValues": [],
"parent": "company",
"type": "number",
"isHidden": false,
"name": "Hours Invested",
"isShared": false,
"filter": [],
"sortOrder": 9,
"isLocked": false
},
{
"_id": "5c94de4752e54d5ce538ae18",
"isFeatured": true,
"listValues": [],
"parent": "invoice",
"type": "text",
"isHidden": false,
"name": "PO Number"
}
]'
https://api.planhat.com/customfields/:_id
To delete an custom field it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/customfields/61043ced0b92efb8a6339cd1' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/endusers
An enduser represents an individual at one of your customers, typically a user of your product, a business contact or both. Endusers can automatically be created based on user tracking events, or based on conversations such as emails and tickets.
Often this automatic creation of contacts along with sync from an external CRM or similar is enough. But there are also situations where you may want to be 100% sure all your users exist in Planhat, and then it would make sense to create them in Planhat over api as soon as they get created in your own system.
If companyId is not present in the payload, and the email has a domain already registered within a company, then Planhat will auto-assign the new enduser to the company using domain matching.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
string | Email address of the enduser/contact. | ||
firstName | string | Enduser first name. | |
lastName | string | Enduser last name | |
name | string | Composed string using the firstName and lastName. This gets autogenerated if the firstName and/or lastName are defined so there is no need to set it. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
externalId | string | The enduser id in your own system. | |
sourceId | string | The enduser id from an integration (Sales Force, Hubspot, etc). | |
position | string | The role or position of this contact/user. e.g, "CFO". | |
phone | string | Enduser phone number, any string will do. | |
tags | array | Array of strings to tag each contact. | |
featured | boolean | Define if the enduser is a feature contact. | |
primary | boolean | Gives extra weighting when assigning emails. | |
archived | boolean | Set the enduser as achived, if the enduser is archived it wont appear in the listing. Defaults to false. | |
sharedNotificationsPrefs | object | Object containing the notification preferences. (Autogenerated). | |
otherEmails | array | Array of extra emails. | |
npsUnsubscribed | boolean | Flag to show if the enduser has unsubcribed to NPS. | |
nps | integer | The last NPS score submitted by the enduser. (Autogenerated). | |
npsComment | string | The comment that was submitted with the NPS score. (Autogenerated). | |
npsDate | string | The date when the last NPS score was received for this enduser. (Autogenerated). | |
npsSent | string | The date when the last NPS survey was sent to this enduser. (Autogenerated). | |
beatTrend | integer | Internal system field. (Autogenerated). | |
beats | integer | Beats count. (Autogenerated). | |
beatsTotal | integer | Total count of beats. (Autogenerated). | |
convs14 | integer | Internal system field. (Autogenerated). | |
convsTotal | integer | Internal system field. (Autogenerated). | |
experience | integer | Internal system field. (Autogenerated). | |
createDate | string | ISO date when enduser was created. (Autogenerated). | |
updatedAt | string | ISO date when enduser was updated. (Autogenerated). | |
lastActivities | array | Array of objects containing the last activities. (Autogenerated). | |
relatedEndusers | array | Array of objects containing the related or duplicate endusers. (Autogenerated). | |
lastTouch | string | ISO date when enduser was last time contacted. (Autogenerated). | |
lastTouchType | string | Type of last contact. (Autogenerated). | |
lastTouchByType | object | Object containing the history of last contact dates by type. (Autogenerated). | |
custom | object | A flexible object with custom data. |
https://api.planhat.com/endusers
To create an enduser it's required define in the payload a companyId and an email, externalId or sourceId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/endusers' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"featured": true,
"email": "jane@test.com",
"firstName": "Jane",
"lastName": "Doe",
"companyId": "61006bc89a3e0b702ed8ea49"
}'
200 OK
'{
"sharedNotificationsPrefs": {
"enabled": [],
"disabled": [],
"disabledEvents": []
},
"otherEmails": [],
"featured": true,
"tags": [],
"npsUnsubscribed": false,
"beatTrend": 0,
"beats": 0,
"convs14": 0,
"convsTotal": 0,
"beatsTotal": 0,
"experience": 0,
"_id": "610091916d643a7c418aef42",
"email": "jane@test.com",
"firstName": "Jane",
"lastName": "Doe",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Tenet",
"name": "Jane Doe",
"createDate": "2021-07-27T23:06:57.083Z",
"lastActivities": [],
"relatedEndusers": [],
"updatedAt": "2021-07-27T23:06:57.086Z",
"emailMd5": "550cf97cea5f2ce1f7f6a5b06c1c51a8",
"__v": 0
}'
https://api.planhat.com/endusers/:_id
To update an enduser it's required to pass the _id in the request URL as a parameter.
Alternately it’s possible to update using the enduser externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/endusers/extid-{{externalId}}
or
https://api.planhat.com/endusers/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/endusers/610091916d643a7c418aef42' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"firstName": "Lara",
"lastName": "Croft"
}'
200 OK
'{
"_id": "610091916d643a7c418aef42",
"sharedNotificationsPrefs": {
"enabled": [],
"disabled": [],
"disabledEvents": []
},
"otherEmails": [],
"featured": true,
"tags": [],
"npsUnsubscribed": false,
"beatTrend": 0,
"beats": 0,
"convs14": 0,
"convsTotal": 0,
"beatsTotal": 0,
"experience": 0,
"email": "jane@test.com",
"firstName": "Lara",
"lastName": "Croft",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Tenet",
"name": "Lara Croft",
"createDate": "2021-07-27T23:06:57.083Z",
"relatedEndusers": [],
"updatedAt": "2021-07-27T23:09:02.889Z",
"emailMd5": "550cf97cea5f2ce1f7f6a5b06c1c51a8",
"__v": 0
}'
https://api.planhat.com/endusers/:_id
To get a specific enduser it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get an enduser using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/endusers/extid-{{externalId}}
or
https://api.planhat.com/endusers/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/endusers/56bccdf554d64d837d01bf42' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "56bccdf554d64d837d01bf42",
"companyId": "56bccdf554d64d837d01be4a",
"companyName": "Google",
"name": "Sadie Santos",
"email": "sadie.santos_5@google.com",
"lastActive": "2021-03-03T00:00:00.000Z",
"beats": 0,
"beatsTotal": 286.01014298852533,
"beatTrend": 0,
"experience": 49,
"firstName": "Sadie",
"lastName": "Santos",
"relevanceRate": 0,
"relevance": 86.82,
"convsTotal": 9,
"convs14": 1,
"tags": [
"Main User"
],
"lastTouch": "2021-07-08T04:00:00.000Z",
"lastTouchType": "QBR",
"lastTouchByType": {
"note": "2019-07-22T18:22:08.774Z",
"Onboarding": "2019-11-11T19:14:16.902Z",
"QBR": "2021-07-08T04:00:00.000Z"
},
"custom": {
"Days in Phase": 0,
"Logins": 0,
"Renewal in days": -1,
"Roles": "role2",
"Activity Count": 0,
"Week No": 29.285714285714285
},
"sourceId": "0030O00002m9M9UQAU",
"createDate": "2016-02-11T18:07:49.000Z",
"emailMd5": "86dcc89d519bb31ea34e4033b0919cab",
"featured": false,
"npsUnsubscribed": false,
"otherEmails": [],
"relatedEndusers": [],
"sharedNotificationsPrefs": {
"disabled": [],
"disabledEvents": [],
"enabled": []
},
"__v": 1,
"updatedAt": "2021-07-12T09:49:56.192Z",
"position": "CSM",
"description": "",
"npsSent": "2021-05-18T16:10:03.468Z"
}'
https://api.planhat.com/endusers
When fetching multiple endusers there are some options that can be used via query params:
companyId: Filter using company id. Multiple ids can be used separating them by commas.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
archived: Passing true the endpoint will include archived endusers.
email: Passing a valid email the endpoint will return a list of endusers with that email.
euId: Passing a valid Planhat ID (_id) the endpoint will return the enduser with that id.
curl --location -g --request GET 'https://api.planhat.com/endusers?limit=2&offset=0' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "56bccdf554d64d837d01bf2c",
"companyId": "56bccdf554d64d837d01be59",
"companyName": "t2",
"name": "John Bakers",
"email": "antonella.silva_1@att.com",
"lastActive": "2021-07-27T02:50:04.000Z",
"beats": 60,
"beatsTotal": 2957.390884043649,
"beatTrend": -3.2,
"experience": 88,
"firstName": "John",
"lastName": "Bakers",
"relevanceRate": 0,
"relevance": 97.11,
"convsTotal": 1,
"convs14": 0,
"tags": [
"Main Contact",
"mahamadou",
"userss",
"New Tag"
],
"lastTouch": "2020-05-05T11:34:48.437Z",
"lastTouchType": "Technical Life-lesson",
"lastTouchByType": {
"Technical Life-lesson": "2020-05-05T11:34:48.437Z"
},
"custom": {
"UserType": "Admin",
"Customer Role": "",
"Days in Phase": 0,
"Logins": 0,
"Renewal in days": -1,
"Roles": "role2",
"Activity Count": 0,
"Week No": 29.285714285714285
},
"sourceId": "0030O00002jbaN1QAI",
"position": "Fireman",
"phone": "07606356442",
"featured": true,
"createDate": "2016-02-11T18:07:49.000Z",
"updatedAt": "2021-07-12T09:49:56.321Z",
"emailMd5": "ea31df0c7a36b8c4c2fcddbe5faa6f4c",
"npsUnsubscribed": false,
"otherEmails": [],
"sharedNotificationsPrefs": {
"disabled": [],
"disabledEvents": [],
"enabled": []
},
"__v": 1,
"companyExternalId": "ATT",
"lastUpdated": "2020-10-07T16:38:47.014Z",
"description": "",
"externalId": "Anton",
"npsSent": "2021-05-18T16:10:03.468Z"
},
{
"_id": "56bccdf554d64d837d01bf42",
"companyId": "56bccdf554d64d837d01be4a",
"companyName": "Google",
"name": "Sadie Santos",
"email": "sadie.santos_5@google.com",
"lastActive": "2021-03-03T00:00:00.000Z",
"beats": 0,
"beatsTotal": 286.01014298852533,
"beatTrend": 0,
"experience": 49,
"firstName": "Sadie",
"lastName": "Santos",
"relevanceRate": 0,
"relevance": 86.82,
"convsTotal": 9,
"convs14": 1,
"tags": [
"Main User"
],
"lastTouch": "2021-07-08T04:00:00.000Z",
"lastTouchType": "QBR",
"lastTouchByType": {
"note": "2019-07-22T18:22:08.774Z",
"Onboarding": "2019-11-11T19:14:16.902Z",
"QBR": "2021-07-08T04:00:00.000Z"
},
"custom": {
"Days in Phase": 0,
"Logins": 0,
"Renewal in days": -1,
"Roles": "role2",
"Activity Count": 0,
"Week No": 29.285714285714285
},
"sourceId": "0030O00002m9M9UQAU",
"createDate": "2016-02-11T18:07:49.000Z",
"emailMd5": "86dcc89d519bb31ea34e4033b0919cab",
"featured": false,
"npsUnsubscribed": false,
"otherEmails": [],
"relatedEndusers": [],
"sharedNotificationsPrefs": {
"disabled": [],
"disabledEvents": [],
"enabled": []
},
"__v": 1,
"updatedAt": "2021-07-12T09:49:56.192Z",
"position": "CSM",
"description": "",
"npsSent": "2021-05-18T16:10:03.468Z"
}
]'
https://api.planhat.com/endusers/:_id
To delete an enduser it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/endusers/610091916d643a7c418aef42' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/endusers
To create an enduser it's required define a companyId, and one of: email, externalId, sourceId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update an enduser it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId, email.
Since this is a bulk upsert operation it's possible create and/or update multiple endusers with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/endusers' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"email": "jane@test.com",
"lastName": "Smith"
},
{
"featured": true,
"email": "will@test.com",
"firstName": "Will",
"lastName": "Smith",
"companyId": "61006bc89a3e0b702ed8ea49"
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "610096a46d643a7c418af043",
"email": "will@test.com"
}
],
"updated": 0,
"updatedErrors": [
{
"item": {
"email": "jane@test.com",
"lastName": "Smith",
"_id": "610091916d643a7c418aef42",
"name": "Lara Smith"
},
"err": [
{
"error": "Not valid type"
}
]
}
],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"610096a46d643a7c418af043"
],
"permissionErrors": []
}'
https://api.planhat.com/invoices
Invoices are normally generated automatically in Planhat when a license is created or renewed, invoices can include multiple line items. Planhat will not prepare invoices that you actually can send to your customers though. They're rather meant to help anyone working with your customers to know the status of current and past invoicing.
Invoices default date fields format should be days format integer. (Days since January 1, 1970, Unix epoch)
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
currency | string | The currency code, for example "USD". There is a "soft" mapping to the id’s in your list of currencies. Technically we accept any string but we recommend using standard currency codes as Ids. Since the mapping is soft you can add sales with a currency code not yet available in your list of currencies. | |
product | string | Name of the sales product. Not required but highly recommended. Even if you only have one product we suggest adding it as "Advanced Onboarding". | |
cId | objectId | Related company id (planhat identifier). | |
cName | string | Company name. (Autogenerated). | |
extId | string | The invoice id in your own system. | |
sourceId | string | The invoice id from an integration (Salesforce, Hubspot, etc). | |
invoiceDate | integer | Date when invoice was created should be in days format integer. | |
lastUpdated | string | ISO date when invoice was updated. (Autogenerated). | |
invoiceNo | integer | Invoice number. (Autogenerated). | |
dueDate | integer | Date when invoice expires in days format integer. | |
paidDate | integer | Date when invoice is paid should be in days format integer. | |
amountTotal | number | Invoice amount. | |
status | string | Status of invoice could be pending, paid, overdue. | |
lineItems | array | Array of license objects. (Autogenerated). | |
emails | array | Internal system field. (Autogenerated). | |
addressCountry | string | Country where the invoice is issued. (Autogenerated). | |
invoiceCycle | string | Cycle of the invoice. Could be one of: monthly, quarterly, yearly, semiAnnual, once or custom. (Autogenerated). | |
custom | object | A flexible object with custom data. |
https://api.planhat.com/invoices
To create an invoice the only real value that is required is the cId but it doesn't make much sense to have an invoice just with a cId, that is why we suggest specify a invoiceDate and currency.
You can instead reference the company externalId or sourceId using the following command structure: "cId": "extid-[company externalId]" or "cId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/invoices' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"dueDate": 19201,
"invoiceDate": 18836,
"currency": "USD",
"amountTotal": 10000,
"lineItems": [
{
"relatedId": "sale-61016c80675c1b871faf2d4f",
"saleId": "61016c80675c1b871faf2d4f",
"product": "Advanced Onboarding",
"amount": 10000,
"dateFrom": 18836
}
],
"cId": "61006bc89a3e0b702ed8ea49"
}'
200 OK
'{
"invoiceNo": 1,
"amountTotal": 10000,
"emails": [],
"status": "pending",
"_id": "61017a0372c0e0884d5e827e",
"dueDate": 19201,
"invoiceDate": 18836,
"currency": "USD",
"lineItems": [
{
"_id": "61017a0372c0e0884d5e827f",
"saleId": "61016c80675c1b871faf2d4f",
"product": "Advanced Onboarding",
"amount": 10000,
"dateFrom": 18836
}
],
"cId": "61006bc89a3e0b702ed8ea49",
"custom": {
"Sent Date": "2021-07-02T04:00:00.000Z",
"Sent": true
},
"cName": "Tenet",
"updatedAt": "2021-07-28T15:38:43.243Z",
"__v": 0
}'
https://api.planhat.com/invoices/:_id
To update a invoice it's required to pass the invoice _id in the request URL as a parameter.
Alternately it’s possible to update using the invoice extId (externalId) adding a prefix and passing this keyable as identifier.
Example:
https://api.planhat.com/invoices/extid-{{extId}}
curl --location -g --request PUT 'https://api.planhat.com/invoices/61017a0372c0e0884d5e827e' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"paidDate": 18840
}'
200 OK
'{
"_id": "61017a0372c0e0884d5e827e",
"invoiceNo": 1,
"amountTotal": 10000,
"emails": [],
"status": "pending",
"dueDate": 19201,
"invoiceDate": 18836,
"currency": "USD",
"lineItems": [
{
"_id": "61017a0372c0e0884d5e827f",
"saleId": "61016c80675c1b871faf2d4f",
"product": "Advanced Onboarding",
"amount": 10000,
"dateFrom": 18836
}
],
"cId": "61006bc89a3e0b702ed8ea49",
"custom": {
"Sent Date": "2021-07-02T04:00:00.000Z",
"Sent": true
},
"cName": "Tenet",
"updatedAt": "2021-07-28T15:56:16.385Z",
"__v": 0,
"paidDate": 18840
}'
https://api.planhat.com/invoices/:_id
To get a specific invoice it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a invoice using its extId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/invoices/extid-{{extId}}
or
https://api.planhat.com/invoices/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/invoices/5bec1521b63ce46d84dd7a7d' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "5bec1521b63ce46d84dd7a7d",
"invoiceNo": 1,
"amountDue": 226029,
"amountPaid": 226029,
"emails": [],
"status": "paid",
"cId": "598b753cc488358437483eb9",
"cName": "Alphabet Inc.",
"invoiceDate": 17752,
"dueDate": 18116,
"lineItems": [
{
"_id": "5bec1521b63ce46d84dd7a7e",
"licenseId": "5baa914c6919c0ec85106069",
"product": "License Fee",
"amount": 244864.75,
"dateFrom": 17752,
"dateTo": 18116
}
],
"__v": 0,
"paidDate": 18673,
"invoiceCycle": "once",
"custom": {
"t1": 0,
"HScore": 0,
"Days in Phase": 0,
"Sent": true,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
},
"updatedAt": "2021-02-15T15:36:41.372Z",
"comments": [],
"amountTotal": 244864.75,
"lastUpdated": "2021-05-28T11:35:12.265Z"
}'
https://api.planhat.com/invoices
When fetching multiple invoices there are some options that can be used via query params:
companyId: Filter using company id. Multiple ids can be used separating them by commas.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/invoices?limit=2&offset=0&sort=-amountTotal&select=_id,product,currency,cId,amountTotal' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "5bec1521b63ce46d84dd7a7d",
"invoiceNo": 1,
"amountDue": 226029,
"amountPaid": 226029,
"emails": [],
"status": "paid",
"cId": "598b753cc488358437483eb9",
"cName": "Alphabet Inc.",
"invoiceDate": 17752,
"dueDate": 18116,
"lineItems": [
{
"_id": "5bec1521b63ce46d84dd7a7e",
"licenseId": "5baa914c6919c0ec85106069",
"product": "License Fee",
"amount": 244864.75,
"dateFrom": 17752,
"dateTo": 18116
}
],
"__v": 0,
"paidDate": 18673,
"invoiceCycle": "once",
"custom": {
"t1": 0,
"HScore": 0,
"Days in Phase": 0,
"Sent": true,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
},
"updatedAt": "2021-02-15T15:36:41.372Z",
"comments": [],
"amountTotal": 244864.75,
"lastUpdated": "2021-05-28T11:35:12.265Z"
},
{
"_id": "5bec958059e144aa751dd7e7",
"invoiceNo": 1,
"amountDue": 150890,
"amountPaid": 0,
"emails": [],
"status": "paid",
"dueDate": 17880,
"invoiceDate": 17850,
"currency": "USD",
"lineItems": [
{
"_id": "5bec958059e144aa751dd7e8",
"licenseId": "598b765d49c568a81b052acc",
"product": "License Fee",
"amount": 150890,
"dateFrom": 17386,
"dateTo": 17746
}
],
"cId": "598b762249c568a81b052a75",
"cName": "Amazon",
"__v": 0,
"custom": {
"t1": 0,
"HScore": 0,
"Days in Phase": 0,
"Sent": true,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
},
"updatedAt": "2020-10-01T13:46:32.781Z",
"amountTotal": 150890,
"paidDate": 18551,
"lastUpdated": "2021-05-28T11:35:12.265Z"
}
]'
https://api.planhat.com/invoices/:_id
To delete a invoice it's required to pass the _id in the request URL as a parameter.
Invoice numbers are immutable. That means that if you have five invoices, 1, 2, 3, 4, 5, and delete the third, you will end with 1, 2, 4, 5 and the next one will be number 6.
curl --location -g --request DELETE 'https://api.planhat.com/invoices/61017a0372c0e0884d5e827e' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/invoices
To create an invoice it's required define a cId, currency and invoiceDate.
You can instead reference the company externalId or sourceId using the following command structure: "cId": "extid-[company externalId]" or "cId": "srcid-[company sourceId]".
To update an invoice it is required to specify in the payload one of the following keyables, listed in order of priority: _id, extId.
Since this is a bulk upsert operation it's possible create and/or update multiple invoices with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/invoices' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"dueDate": 19201,
"invoiceDate": 18834,
"currency": "USD",
"amountTotal": 10000,
"lineItems": [
{
"relatedId": "sale-61016c80675c1b871faf2d4f",
"saleId": "61016c80675c1b871faf2d4f",
"product": "Advanced Onboarding",
"amount": 10000,
"dateFrom": 18836
}
],
"cId": "61006bc89a3e0b702ed8ea49"
},
{
"dueDate": 19210,
"invoiceDate": 18832,
"currency": "USD",
"amountTotal": 15000,
"lineItems": [
{
"relatedId": "sale-61016c80675c1b871faf2d4f",
"saleId": "61016c80675c1b871faf2d4f",
"product": "Advanced Onboarding",
"amount": 10000,
"dateFrom": 18836
}
],
"cId": "61006bc89a3e0b702ed8ea49"
}
]'
200 OK
'{
"created": 2,
"createdErrors": [],
"insertsKeys": [
{
"_id": "6101954772c0e0884d5e8b4f"
},
{
"_id": "6101954772c0e0884d5e8b50"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"6101954772c0e0884d5e8b4f",
"6101954772c0e0884d5e8b50"
],
"permissionErrors": []
}'
https://api.planhat.com/issues
Issues typically represent Bugs or Feature Requests. Many of our customers fetch issues from Jira, but they can also be pushed to Planhat from other product management tools such as Product Board or Aha! You can also manage issues directly in Planhat without any external tool. Just keep in mind that the functionality is basic and mostly intended to contribute to the customer 360 view.
Issues in Planhat can link to multiple companies, to multiple endusers and to multiple conversations.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
title | string | Issue title, required to create an issue. | |
description | string | Description for the issue. | |
companyIds | array | Array of companies ids involved with the issue. | |
companies | array | Array of companies involved with the issue. (Autogenerated). | |
enduserIds | array | Array of endusers ids that are part of the issue. | |
endusers | array | Array of endusers that are part of the issue. (Autogenerated). | |
conversationIds | array | Array of conversations ids that are part of the issue. | |
sourceId | string | The issue id from an integration (Sales Force, Hubspot, etc). | |
source | string | Source name or description. | |
sourceUrl | string | Source URL. | |
priority | string | Priority name or description. | |
archived | boolean | True is the issued is archived. | |
status | string | Current status of the issue. | |
mrrCombined | integer | Total MRR involved in this issue. (Autogenerated). | |
arrCombined | integer | Total ARR involved in this issue. (Autogenerated). | |
createdAt | string | ISO date when issue was created. (Autogenerated). | |
updatedAt | string | ISO date when issue was updated. (Autogenerated). | |
followers | array | Array of users ids following the issue. | |
custom | object | A flexible object with custom data. |
https://api.planhat.com/issues
To create a issue the only real value that is required is the title but it doesn't make much sense to have an issue just with a title, that is why we suggest specify a companyIds.
You can instead reference the company externalId or sourceId using the following command structure: "companyIds": ["extid-[company externalId]"] or "companyIds": ["srcid-[company sourceId]"].
curl --location -g --request POST 'https://api.planhat.com/issues' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"companyIds": [
"61006bc89a3e0b702ed8ea49"
],
"enduserIds": [
"610091916d643a7c418aef42"
],
"title": "Problem with integration",
"description": "There is a problem with our integration settings that is affecting some users.",
"status": "Open"
}'
200 OK
'{
"companyMatchingValue": [],
"companyIds": [
"61006bc89a3e0b702ed8ea49"
],
"enduserIds": [
"610091916d643a7c418aef42"
],
"conversationIds": [],
"archived": false,
"_id": "610411d5b046afb2109df12c",
"title": "Problem with integration",
"description": "There is a problem with our integration settings that is affecting some users.",
"status": "Open",
"companies": [
{
"id": "61006bc89a3e0b702ed8ea49",
"name": "Tenet"
}
],
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Lara Croft"
}
],
"updatedAt": "2021-07-30T14:51:01.691Z",
"createdAt": "2021-07-30T14:51:01.691Z",
"__v": 0
}'
https://api.planhat.com/issues/:_id
To update a issue it's required to pass the issue _id in the request URL as a parameter.
curl --location -g --request PUT 'https://api.planhat.com/issues/610411d5b046afb2109df12c' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"status": "In Progress"
}'
200 OK
'{
"_id": "61041245b046afb2109df1bb",
"companyMatchingValue": [],
"companyIds": [
"61006bc89a3e0b702ed8ea49"
],
"enduserIds": [],
"conversationIds": [],
"archived": false,
"title": "Problem with integration",
"description": "There is a problem with our integration settings that is affecting some users.",
"status": "In Progress",
"companies": [
{
"id": "61006bc89a3e0b702ed8ea49",
"name": "Tenet"
}
],
"endusers": [],
"updatedAt": "2021-07-30T14:52:53.441Z",
"createdAt": "2021-07-30T14:52:53.441Z",
"__v": 0
}'
https://api.planhat.com/issues/:_id
To get a specific issue it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a issue using its sourceId adding a prefix and passing this keyable as identifier.
Example:
https://api.planhat.com/issues/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/issues/60f7df113432fd36abf8b899' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "60f7df113432fd36abf8b899",
"companyMatchingValue": [],
"companyIds": [
"56bccdf554d64d837d01be9d"
],
"enduserIds": [],
"conversationIds": [],
"archived": false,
"title": "There is a problem with the sites",
"companies": [],
"endusers": [],
"updatedAt": "2021-07-21T08:47:13.221Z",
"createdAt": "2021-07-21T08:47:13.221Z",
"__v": 0,
"status": "Done"
}'
https://api.planhat.com/issues
When fetching multiple issues there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/issues?limit=2&offset=0&sort=-createdAt&select=_id,title,status,companyIds' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "61041245b046afb2109df1bb",
"companyIds": [
"61006bc89a3e0b702ed8ea49"
],
"title": "Problem with integration",
"status": "In Progress"
},
{
"_id": "61002501cb43626b3a802f52",
"companyIds": [
60f7df113432fd36abf8b899
],
"title": "New issue",
"status": "Done"
}
]'
https://api.planhat.com/issues/:_id
To delete an issue it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/issues/610411d5b046afb2109df12c' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/issues
To create an issue it's required define a title and companyIds.
You can instead reference the company externalId or sourceId using the following command structure: "companyIds": ["extid-[company externalId]"] or "companyIds": ["srcid-[company sourceId]"].
To update an issue it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId.
Since this is a bulk upsert operation it's possible create and/or update multiple issues with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/issues' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"_id": "60f7df113432fd36abf8b899",
"status": "Done"
},
{
"companyIds": [
"61006bc89a3e0b702ed8ea49"
],
"enduserIds": [
"610091916d643a7c418aef42"
],
"title": "Problem with integration",
"description": "There is a problem with our integration settings that is affecting some users.",
"status": "Open"
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "610415ecb046afb2109df26b"
}
],
"updated": 1,
"updatedErrors": [],
"updatesKeys": [
{
"_id": "60f7df113432fd36abf8b899"
}
],
"nonupdates": 0,
"modified": [
"60f7df113432fd36abf8b899"
],
"upsertedIds": [
"610415ecb046afb2109df26b"
],
"permissionErrors": []
}'
https://api.planhat.com/licenses
Licenses represent your customers' subcriptions to your service and is the base for MRR (or ARR) calculations and most revenue reports. For non recurring revenue, please see the Sale (NRR) object. There are many ways to get license data into Planhat including incomming webhooks and CRM integrations. In some case though, you just want to handle it yourself over the api, for example if the main source of license data is your own system.
Licenses in Planhat can be fixed period with a defined start and end date. Or they can be non fixed period (sometimes called open-ended or evergreen). Open ended licenses initially don't have a specified end date since the customer may cancel at any time.. once the license is churned/lost also non fixed period licenses can have an end date.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
product | string | Name of the license product. Not required but highly recommended. Even if you only have one product we suggest adding it as "License Fee" or "Subscription". | |
_currency | string | The currency code, for example "USD". There is a "soft" mapping to the id’s in your list of currencies. Technically we accept any string but we recommend using standard currency codes as Ids. Since the mapping is soft you can add licenses with a currency code not yet available in your list fo currencies. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
externalId | string | The license id in your own system. | |
sourceId | string | The license id from an integration (Sales Force, Hubspot, etc). | |
fromDate | string | Start of the license period (ISO format). | |
toDate | string | End of the license period (ISO format). | |
fixedPeriod | boolean | Boolean to indicate if this is an ongoing license (no defined end date) or license with a fixed term. Non fixed-term licenses require an mrr value specified, whereas fixed-term licenses specify the value over the whole period. Defaults to false. | |
mrr | number | Monthly license value (required if fixedPeriod is false). | |
arr | number | Annual license value. | |
renewalMrr | number | Renewal MRR. | |
renewalArr | number | Renewal ARR. | |
fcNewMrr | number | Monthly value forecast. | |
fcNewArr | number | Annual value forecast. | |
fcNewMrrOptimistic | number | Optimistic monthly value forecast. | |
fcNewArrOptimistic | number | Optimistic annual value forecast. | |
fcNewMrrPessimistic | number | Pessimistic monthly value forecast. | |
fcNewArrPessimistic | number | Pessimistic annual value forecast. | |
value | number | The total license value for the whole subscription period, must be positive (required if fixedPeriod is true and no mrr value). | |
renewalStatus | string | Can take one of the following values: 'ongoing', 'renewed', 'lost'. | |
renewalPeriod | integer | Defines the length of the next license period if the subscription should be renewed. Defaults to 1, which would mean the license renews with a new 1-month period, regardless of the length of the current license period. If the renewalPeriod is not set, it will be assumed that the contract renews on the same period as previous. If the license isn’t set to autorenew the renewalPeriod will only serve as guidance for the manual input. | |
renewalDate | string | ISO date when license will be renewed. (Autogenerated). | |
renewalDaysFromNow | integer | Number of days till the next renewal. (Autogenerated). | |
isOverdue | boolean | Flag the license as overdue. (Autogenerated). | |
autoRenews | boolean | If set to true Planhat can automatically renew the subscription for you once the notice period is passed. Necessary for noticePeriod and noticeUnit to be autogenerated. Defaults to false. | |
noticePeriod | integer | Number of days/weeks/months before subscription ends that the license would have to be canceled not to automatically renew. Only makes sense if autoRenews is set to true. Defaults to 0. (Autogenerated). | |
noticeUnit | string | Unit for the noticePeriod, could be days/weeks/months. (Autogenerated). | |
renewalUnit | string | Unit for the noticePeriod, could be day/week/month. Defaults to month. | |
parent | string | Planhat ID of the ultimate parent license. | |
invoicesGenerated | boolean | Set to true for the invoices to not be autogenerated for the license upon creation. Default: false. | |
invoiceMuted | boolean | Set to true to disable the invoices creation when license renewal. Default: false. | |
invoiceCycleInterval | integer | Defines the custom cycle interval. (Autogenerated). | |
invoiceCycle | string | Cycle of the invoice. Could be one of: monthly, quarterly, yearly, semiAnnual, once or custom. (Autogenerated). | |
toDateIncluded | boolean | Set to true if the license has toDate (Autogenerated). | |
length | number | Internal system field. (Autogenerated). | |
custom | object | A flexible object with custom data. |
https://api.planhat.com/licenses
To create a lincese the only real value that is required is the companyId but it doesn't make much sense to have a license just with a companyId, that is why we suggest specify a value, _currency and fromDate.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/licenses' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"autoRenews": false,
"companyId": "61006bc89a3e0b702ed8ea49",
"fixedPeriod": true,
"fromDate": "2021-07-27T00:00:00.000Z",
"toDate": "2022-07-27T00:00:00.000Z",
"mrr": 83.33333333333333,
"product": "Large License",
"_currency": "USD",
"renewalPeriod": 12,
"renewalStatus": "ongoing"
}'
200 OK
'{
"renewalStatus": "ongoing",
"issues": [],
"autoRenews": false,
"noticePeriod": null,
"renewalUnit": "month",
"noticeUnit": null,
"invoicesGenerated": false,
"_id": "61006fbf1df7fa77a20d9d0a",
"companyId": "61006bc89a3e0b702ed8ea49",
"fixedPeriod": true,
"fromDate": "2021-07-27T00:00:00.000Z",
"toDate": "2022-07-27T00:00:00.000Z",
"invoiceCycleInterval": 0,
"mrr": 83.33333333333333,
"product": "Large License",
"_currency": "USD",
"renewalPeriod": 12,
"companyName": "Tenet",
"toDateIncluded": false,
"length": 12,
"value": 1000,
"renewalDate": "2022-07-27T00:00:00.000Z",
"renewalDaysFromNow": 364,
"isOverdue": false,
"__v": 0
}'
https://api.planhat.com/licenses/:_id
To update a license it's required to pass the license _id in the request URL as a parameter.
Alternately it’s possible to update using the license externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/licenses/extid-{{externalId}}
or
https://api.planhat.com/licenses/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/licenses/61006fbf1df7fa77a20d9d0a' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"mrr": 100000
}'
200 OK
'{
"_id": "61006fbf1df7fa77a20d9d0a",
"renewalStatus": "ongoing",
"issues": [],
"autoRenews": false,
"noticePeriod": null,
"renewalUnit": "month",
"noticeUnit": null,
"invoicesGenerated": false,
"companyId": "61006bc89a3e0b702ed8ea49",
"fixedPeriod": true,
"fromDate": "2021-07-27T00:00:00.000Z",
"toDate": "2022-07-27T00:00:00.000Z",
"invoiceCycleInterval": 0,
"mrr": 100000,
"product": "Large License",
"_currency": "USD",
"renewalPeriod": 12,
"companyName": "Tenet",
"toDateIncluded": false,
"length": 12,
"value": 1200000,
"renewalDate": "2022-07-27T00:00:00.000Z",
"renewalDaysFromNow": 364,
"isOverdue": false,
"__v": 0
}'
https://api.planhat.com/licenses/:_id
To get a specific license it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a license using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/licenses/extid-{{externalId}}
or
https://api.planhat.com/licenses/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/licenses/56bccdf554d64d837d01beb2' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "56bccdf554d64d837d01beb2",
"renewalStatus": "renewed",
"issues": null,
"autoRenews": false,
"noticePeriod": null,
"renewalUnit": "month",
"noticeUnit": null,
"invoicesGenerated": false,
"isOverdue": false,
"renewalDaysFromNow": -1313,
"renewalDate": "2017-12-22T00:00:00.000Z",
"mrr": 1958.3333333333333,
"length": 24,
"fixedPeriod": true,
"product": "",
"value": 47000,
"_currency": "USD",
"fromDate": "2015-12-22T00:00:00.000Z",
"toDate": "2017-12-22T00:00:00.000Z",
"salesDate": "2015-12-22T18:07:49.000Z",
"renewalPeriod": 24,
"toDateIncluded": false,
"invoiceCycleInterval": 0,
"sourceId": "0060O00000xdyr4QAA",
"companyId": "56bccdf554d64d837d01beaf",
"companyName": "Siemens",
"custom": {
"Days in Phase": 0,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Days until renewal": -1,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
}
}'
https://api.planhat.com/licenses
When fetching multiple licenses there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/licenses?limit=2&offset=0&sort=-value&select=_id,product,value,companyId' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "601188a152181c5640bf429f",
"companyId": "6011889f52181c5640bf41bb",
"value": 292500
},
{
"_id": "598b7911c488358437484797",
"value": 280950,
"product": "",
"companyId": "598b78ef49c568a81b052f49"
}
]'
https://api.planhat.com/licenses/:_id
To delete a license it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/licenses/61006fbf1df7fa77a20d9d0a' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/licenses
To create a license it's required define a companyId, _currency and value.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a license it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple licenses with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/licenses' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"_id": "6100772b919fd37905810fc6",
"mrr": 200000
},
{
"autoRenews": false,
"companyId": "61006bc89a3e0b702ed8ea49",
"fixedPeriod": true,
"fromDate": "2021-07-28T00:00:00.000Z",
"toDate": "2022-07-28T00:00:00.000Z",
"invoiceCycleInterval": 0,
"mrr": 100,
"product": "Large License",
"_currency": "USD",
"renewalPeriod": 12,
"renewalStatus": "ongoing"
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "61007752919fd37905810ff5"
}
],
"updated": 1,
"updatedErrors": [],
"updatesKeys": [
{
"_id": "6100772b919fd37905810fc6"
}
],
"nonupdates": 0,
"modified": [
"6100772b919fd37905810fc6"
],
"upsertedIds": [
"61007752919fd37905810ff5"
],
"permissionErrors": []
}'
https://api.planhat.com/conversations
Notes in Planhat are technically Conversations. You can create your own custom Touch Types to easily distinguish between different types of notes. You can also use custom fields to add more nuance to your Notes.
It's quite common for Notes in Planhat to sync with external systems such as Salesforce, Notes can also be created via Zapier or Planhats's native incoming webhooks.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
companyId | objectId | Related company id (planhat identifier). | |
subject | string | Title of the note. | |
description | string | Description of the note. | |
date | string | Date when note was created. In ISO format. | |
activityTags | array | Array of tag's objectId. | |
users | array | Array of user's objects. | |
companyExternalId | string | The External Company Id. | |
type | string | For this model should be note. | |
endusers | array | Array of enduser's objects. | |
custom | object | A flexible object with custom data. |
https://api.planhat.com/conversations
To create an note it's required define in the payload a companyId and type as note.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/conversations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"users": [
{
"id": "5d66266e187f60020bc8036f",
"name": "Ivars",
"isOwner": true
}
],
"date": "2021-08-22T16:15:50.772Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "Support with Tenet",
"description": "Support session with the client",
"activityTags": [
"5f514794dc005f275e9cc20c"
],
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Jane Doe"
}
]
}'
200 OK
'{
"starred": false,
"pinned": false,
"autoTags": [],
"activityTags": [
"5f514794dc005f275e9cc20c"
],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"timeBucket": [],
"archived": false,
"_id": "61081aede03cf31e13ea1e51",
"users": [
{
"id": "5d66266e187f60020bc8036f",
"name": "Ivars",
"isOwner": true
}
],
"date": "2021-08-22T16:15:50.772Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "Support with Tenet",
"description": "Support session with the client",
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Jane Doe"
}
],
"snippet": "Support session with the client",
"companyName": "Tenet",
"createDate": "2021-08-02T16:18:53.730Z",
"sender": [],
"history": [],
"__v": 0,
"companySourceId": "119",
"owner": "60ccb1c5965cc9e0f3848075",
"followers": [],
"userId": "610015551b990c65d4fb0a4c",
"note": "Support with Tenet: Support session with the client",
"nickName": "Jest tests"
}'
https://api.planhat.com/conversations/:_id
To update an notes it's required to pass the _id in the request URL as a parameter.
curl --location -g --request PUT 'https://api.planhat.com/conversations/61081aede03cf31e13ea1e51' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"subject": "Possible upgrade",
"description": "The client is insterested in a subscription upgrade.
"
}'
200 OK
'{
"_id": "61081aede03cf31e13ea1e51",
"starred": false,
"pinned": false,
"autoTags": [],
"activityTags": [
"5f514794dc005f275e9cc20c"
],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"timeBucket": [],
"archived": false,
"users": [
{
"id": "5d66266e187f60020bc8036f",
"name": "Ivars",
"isOwner": true
}
],
"date": "2021-08-22T16:15:50.772Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "Possible upgrade",
"description": "The client is insterested in a subscription upgrade.
",
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Jane Doe"
}
],
"snippet": "The client is insterested in a subscription upgrade.",
"companyName": "Tenet",
"createDate": "2021-08-02T16:18:53.730Z",
"sender": [],
"history": [],
"__v": 0
}'
https://api.planhat.com/conversations/:_id
To get a specific note it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a note using its externalId adding a prefix and passing this keyable as identifiers.
Example:
https://api.planhat.com/conversations/extid-{{externalId}}
curl --location -g --request GET 'https://api.planhat.com/conversations/60fee824a4c764252c877c2b' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"date": "2021-07-26T16:51:44.146Z",
"userIds": [
"5f16fd8eee876638a9f2483c"
],
"isCustomType": false,
"subject": "t6",
"_id": "60fee824a4c764252c877c2b",
"type": "note",
"tags": [],
"createDate": "2021-07-26T16:51:48.720Z",
"companyId": "584d9d5505ba1b622f04adb3",
"companyName": "Daimler North America",
"users": [
{
"id": "5f16fd8eee876638a9f2483c",
"name": "Ernesto",
"isOwner": true
}
],
"endusers": [],
"assigneeName": "",
"activityTags": [],
"hasAttachments": false,
"isSeen": false,
"starred": false,
"pinned": false,
"archived": false,
"custom": {
"Activity Count": 0,
"Days in Phase": 0,
"Logins": 0
}
}'
https://api.planhat.com/conversations
When fetching multiple notes there are some options that can be used via query params:
companyId: Filter using company id. Multiple ids can be used separating them by commas.
limit: Limit the list length. Default as 30, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/conversations?limit=2&offset=0' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"date": "2021-07-29T15:29:34.330Z",
"userIds": [
"58e231b14246fc73139f29e8"
],
"hasMore": false,
"isCustomType": false,
"subject": "Chat with the client",
"snippet": "Slack chat with the client.",
"_id": "6102e3b08084189dcbf0e3f0",
"type": "note",
"tags": [],
"createDate": "2021-07-29T17:21:52.347Z",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Leo company",
"users": [
{
"id": "58e231b14246fc73139f29e8",
"name": "Alex",
"isOwner": true
}
],
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Lara Croft"
}
],
"assigneeName": "",
"activityTags": [],
"hasAttachments": false,
"isSeen": false,
"starred": false,
"pinned": false,
"archived": false
},
{
"date": "2021-07-26T16:51:44.146Z",
"userIds": [
"5f16fd8eee876638a9f2483c"
],
"isCustomType": false,
"subject": "t6",
"_id": "60fee824a4c764252c877c2b",
"type": "note",
"tags": [],
"createDate": "2021-07-26T16:51:48.720Z",
"companyId": "584d9d5505ba1b622f04adb3",
"companyName": "Daimler North America",
"users": [
{
"id": "5f16fd8eee876638a9f2483c",
"name": "Ernesto",
"isOwner": true
}
],
"endusers": [],
"assigneeName": "",
"activityTags": [],
"hasAttachments": false,
"isSeen": false,
"starred": false,
"pinned": false,
"archived": false,
"custom": {
"Activity Count": 0,
"Days in Phase": 0,
"Logins": 0
}
}
]'
https://api.planhat.com/conversations/:_id
To delete an note it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/conversations/61081aede03cf31e13ea1e51' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"starred": false,
"pinned": false,
"autoTags": [],
"activityTags": [
"5f514794dc005f275e9cc20c"
],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"timeBucket": [],
"archived": false,
"_id": "61081aede03cf31e13ea1e51",
"users": [
{
"id": "5d66266e187f60020bc8036f",
"name": "Ivars",
"isOwner": true
}
],
"date": "2021-08-22T16:15:50.772Z",
"type": "note",
"companyId": "61006bc89a3e0b702ed8ea49",
"subject": "Possible upgrade",
"description": "The client is insterested in a subscription upgrade.
",
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Jane Doe"
}
],
"snippet": "The client is insterested in a subscription upgrade.",
"companyName": "Tenet",
"createDate": "2021-08-02T16:18:53.730Z",
"sender": [],
"history": [],
"__v": 0
}'
https://api.planhat.com/conversations
To create a note it's required define a companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a note it is required to specify in the payload the _id.
Since this is a bulk upsert operation it's possible create and/or update multiple projects with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/conversations' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"users": [
{
"id": "5d66266e187f60020bc8036f",
"name": "Ivars",
"isOwner": true
}
],
"date": "2021-08-22T16:15:50.772Z",
"type": "note",
"companyId": "{{companyId}}",
"subject": "Support with Tenet",
"description": "Support session with the client",
"activityTags": [
"5f514794dc005f275e9cc20c"
],
"endusers": [
{
"id": "610091916d643a7c418aef42",
"name": "Jane Doe"
}
]
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "61672167d4ac8780f8f680af"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"61672167d4ac8780f8f680af"
],
"permissionErrors": []
}'
https://api.planhat.com/nps
NPS records in Planhat represent the individual responses to an nps survey. Typically these are created automatically when running an nps campaign in Planhat, or in some cases imported from external NPS tools. A single enduser/contact can have multiple records if they responded to different surveys over time.
Based on the NPS records each enduser and company in Planhat also get an nps score assigned.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
cId | objectId | Related company id (planhat identifier). | |
string | Email of the contact that has been surveyed. | ||
euId | objectId | Enduser id. (Autogenerated). | |
campaignId | objectId | ID of the campaign associated with the NPS. | |
score | integer | Feedback score that the user submit in his/her survey (0-10). | |
comment | string | The comment when the user gives an score in survey. | |
sourceId | string | The project id from an integration (Sales Force, Hubspot, etc). | |
dateSent | string | ISO date when the survey was sent. | |
dateAnswered | string | ISO date when the survey was answered. | |
source | string | The name of the system that NPS scores come from. For example: "custom-nps.com". | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/nps
To create an NPS it's required define an enduser email and a score.
curl --location -g --request POST 'https://api.planhat.com/nps' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"email": "jane@test.com",
"score": 7
}'
200 OK
'{
"_id": "61030b0e8084189dcbf0e6da",
"email": "jane@test.com",
"score": 7,
"euId": "610091916d643a7c418aef42",
"cId": "61006bc89a3e0b702ed8ea49",
"scoreType": "passive",
"dateSent": null,
"dateAnswered": "2021-07-29T20:09:50.914Z",
"__v": 0
}'
https://api.planhat.com/nps/:_id
To update an NPS it's required to pass the NPS _id in the request URL as a parameter.
Alternately it’s possible to update using the NPS sourceId adding a prefix.
Example:
https://api.planhat.com/nps/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/nps/61030b0e8084189dcbf0e6da' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"score": 9,
"comment": "Good product"
}'
200 OK
'{
"_id": "61030b0e8084189dcbf0e6da",
"campaignId": "60915415fc985e73734f5c02",
"email": "jane@test.com",
"score": 9,
"euId": "610091916d643a7c418aef42",
"cId": "61006bc89a3e0b702ed8ea49",
"scoreType": "promoter",
"dateSent": null,
"dateAnswered": "2021-07-29T20:09:50.914Z",
"__v": 0,
"comment": "Good product"
}'
https://api.planhat.com/nps/:_id
To get a specific NPS it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a NPS using its sourceId adding a prefix.
Example:
https://api.planhat.com/nps/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/nps/5a2692f13a3f1f4202cf281f' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "5a2692f13a3f1f4202cf281f",
"npsId": "5f3bc3efe8cd350bb6cf715a",
"email": "taco@trello.com",
"npsDate": "2020-09-14T06:20:59.367Z",
"nps": 6,
"npsComment": null,
"npsSent": null,
"scoreType": "detractor",
"cId": "598b76adc488358437484229",
"campaignId": "5c3d0c38b95614b78f100c65",
"dateSent": "2020-08-18T12:10:03.495Z",
"dateReminderSent": null,
"source": "Planhat",
"sourceId": "5f3bc3efe8cd350bb6cf715a",
"custom": null
}'
https://api.planhat.com/nps
When fetching multiple NPS there are some options that can be used via query params:
companyId: Filter using company id. Multiple ids can be used separating them by commas.
limit: Limit the list length. Default as 100, max. 10000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
npsExpiryDay: Integer representing the number of days before the curret date where the
NPS was answered. The default value is 360, meaning that be default you will get NPS answered from 1 year to the current date.curl --location -g --request GET 'https://api.planhat.com/nps?limit=2&offset=0' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "58a161c86ffa1e5706ca4e81",
"npsId": "5f0f2312d8c9ff05273778c5",
"email": "david.lundstrom@sweco.se",
"npsDate": "2020-08-06T00:00:00.000Z",
"nps": 8,
"npsComment": "Good one",
"npsSent": null,
"scoreType": "passive",
"cId": "56bccdf554d64d837d01be55",
"campaignId": null,
"dateSent": "2020-06-06T00:00:00.000Z",
"dateReminderSent": null,
"source": null,
"sourceId": "",
"custom": null
},
{
"_id": "5a2692f13a3f1f4202cf281f",
"npsId": "5f3bc3efe8cd350bb6cf715a",
"email": "taco@trello.com",
"npsDate": "2020-09-14T06:20:59.367Z",
"nps": 6,
"npsComment": null,
"npsSent": null,
"scoreType": "detractor",
"cId": "598b76adc488358437484229",
"campaignId": "5c3d0c38b95614b78f100c65",
"dateSent": "2020-08-18T12:10:03.495Z",
"dateReminderSent": null,
"source": "Planhat",
"sourceId": "5f3bc3efe8cd350bb6cf715a",
"custom": null
}
]'
https://api.planhat.com/nps/:_id
To delete an NPS it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/nps/61030b0e8084189dcbf0e6da' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/nps
To create a NPS it's required define an enduser email and a score.
To update a NPS it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId.
Since this is a bulk upsert operation it's possible create and/or update multiple NPS with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/nps' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"email": "jane@test.com",
"score": 7
},
{
"email": "pepe@test.com",
"score": 10
}
]'
200 OK
'{
"created": 2,
"createdErrors": [],
"insertsKeys": [
{
"_id": "610313dee41b0aa81c926b69"
},
{
"_id": "610313dee41b0aa81c926b6a"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"610313dee41b0aa81c926b69",
"610313dee41b0aa81c926b6a"
],
"permissionErrors": []
}'
https://api.planhat.com/opportunities
Opportunities in Planhat represent a sales opportunity, whether it's selling to a new customer or more commonly a chance of expanding an existing account.
Opportunities are not the sames as Licenses, but when an opportunity is closed won in Planhat, there is an optional setting to generate a licenses based on the opportunity data.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
salesStage | string | Sales stage of opportunity. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
dealDate | string | Deal date in ISO format. | |
landingDate | string | Landing date of the opportunity in ISO format. | |
closeDate | string | Close date of the opportunity in ISO format. | |
externalId | string | The project id in your own system. | |
sourceId | string | The opportunity id from an integration (Salesforce, Hubspot, etc). | |
_currency | string | The currency code, for example "USD". | |
title | string | Title of sales opportunity. | |
ownerId | objectId | ObjectId of the team member owner of the opportunity. | |
mrr | number | Monthly opportunity value. | |
arr | number | Annual opportunity value. | |
nrr | number | Non recurrent value. | |
contractLength | integer | Contract Length (months, defaults to 12). | |
status | string | Status of the opportunity, could be: active, won or lost. | |
stageHistory | array | Array of object containing the history of this opportunity. (Autogenerated). | |
probability | number | Probability of wining the opportunity. | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/opportunities
To create an opportunity it's required define a companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/opportunities' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"salesStage": "Pitched",
"dealDate": "2021-08-03T00:00:00.000Z",
"ownerId": "60ccb1c5965cc9e0f3848075",
"_currency": "USD",
"companyId": "61006bc89a3e0b702ed8ea49",
"title": "New opportunity",
"recurringValue": 3000,
"mrr": 250,
"nrr": 500,
"status": "active"
}'
200 OK
'{
"status": "active",
"_id": "6101e99b72c0e0884d5e9139",
"salesStage": "Pitched",
"dealDate": "2021-08-03T00:00:00.000Z",
"ownerId": "60ccb1c5965cc9e0f3848075",
"_currency": "USD",
"companyId": "61006bc89a3e0b702ed8ea49",
"title": "New opportunity",
"mrr": 250,
"nrr": 500,
"companyName": "Tenet",
"stageHistory": [],
"landingDate": "2021-07-28T23:34:51.636Z",
"__v": 0
}'
https://api.planhat.com/opportunities/:_id
To update an opportunity it's required to pass the opportunity _id in the request URL as a parameter.
Alternately it’s possible to update using the opportunity externalId adding a prefix and passing this keyable as identifier.
Example:
https://api.planhat.com/opportunities/extid-{{externalId}}
curl --location -g --request PUT 'https://api.planhat.com/opportunities/6101e99b72c0e0884d5e9139' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"status": "won",
"salesStage": "Closed won"
}'
200 OK
'{
"_id": "6101e99b72c0e0884d5e9139",
"status": "won",
"salesStage": "Closed won",
"dealDate": "2021-08-03T00:00:00.000Z",
"ownerId": "60ccb1c5965cc9e0f3848075",
"_currency": "USD",
"companyId": "61006bc89a3e0b702ed8ea49",
"title": "New opportunity",
"mrr": 250,
"nrr": 500,
"companyName": "Leo company",
"stageHistory": [],
"landingDate": "2021-07-28T23:34:51.636Z",
"__v": 0,
"closeDate": "2021-07-28T23:36:59.294Z"
}'
https://api.planhat.com/opportunities/:_id
To get a specific opportunity it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get an opportunity using its externalId and/or sourceId adding a prefix and passing one of these keyable as identifier.
Example:
https://api.planhat.com/opportunities/extid-{{externalId}}
or
https://api.planhat.com/opportunities/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/opportunities/58499569e2914f5171fa7f9d' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "58499569e2914f5171fa7f9d",
"status": "lost",
"companyId": "56bccdf554d64d837d01be86",
"stageHistory": [
{
"stage": "opportunity",
"to": "2016-12-08T17:16:25.153Z"
}
],
"landingDate": "2018-11-29T11:57:06.444Z",
"comments": [],
"__v": 0,
"custom": null,
"companyName": "Toyota"
}'
https://api.planhat.com/opportunities
When fetching multiple opportunities there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/opportunities?limit=2&offset=0&sort=-mrr&select=_id,title,status' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "5ced0734861084738e27ff21",
"status": "lost",
"title": "P1 enabled!"
},
{
"_id": "5804f2e90abc84bf13ac5cd7",
"title": "Up sell Opportunity",
"status": "won"
}
]'
https://api.planhat.com/opportunities/:_id
To delete an opportunity it's required to pass the opportunity _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/opportunities/6101e99b72c0e0884d5e9139' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/opportunities
To create a opportunity it's required define a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a opportunity it is required to specify in the payload one of the following keyables, listed in order of priority: _id, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple projects with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/opportunities' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"salesStage": "Pitched",
"dealDate": "2021-08-10T00:00:00.000Z",
"ownerId": "60ccb1c5965cc9e0f3848075",
"_currency": "USD",
"companyId": "61006bc89a3e0b702ed8ea49",
"title": "New license opportunity",
"recurringValue": 6000,
"status": "active"
},
{
"salesStage": "Pitched",
"dealDate": "2021-08-03T00:00:00.000Z",
"ownerId": "60ccb1c5965cc9e0f3848075",
"_currency": "USD",
"companyId": "61006bc89a3e0b702ed8ea49",
"title": "New sale opportunity",
"recurringValue": 1000,
"status": "active"
}
]'
200 OK
'{
"created": 2,
"createdErrors": [],
"insertsKeys": [
{
"_id": "6101ebd072c0e0884d5e91fb"
},
{
"_id": "6101ebd072c0e0884d5e91fc"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"6101ebd072c0e0884d5e91fb",
"6101ebd072c0e0884d5e91fc"
],
"permissionErrors": []
}'
https://api.planhat.com/objectives
Being very clear and focused on your goals with customers is critical, and now you can track objectives and the health per objective.
Pro-tip: use your average Objective health in the Health Score!
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
name | string | Objective name. | |
health | number | Objective health. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
externalId | string | The objective id in your own system. | |
sourceId | string | The objective id from an integration (Sales Force, Hubspot, etc). | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/objectives
To create an objective it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/objectives' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Objective name",
"health": 5,
"companyId": "60df26bfa259250cba9cf816",
"externalId": 1234,
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
}
}'
200 OK
'{
"_id": "60faeda853b8f717ebe36146",
"name": "Objective name",
"health": 5,
"companyId": "60df26bfa259250cba9cf816",
"externalId": "1234",
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
},
"companyName": "Test Company"
}'
https://api.planhat.com/objectives/:_id
To update an objective it's required to pass the _id in the request URL as a parameter.
Alternately it’s possible to update using the objective externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/objectives/extid-{{externalId}}
or
https://api.planhat.com/objectives/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/objectives/60faeda853b8f717ebe36146' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Objective name 2"
}'
200 OK
'{
"_id": "60ff061d681a6b4da9248694",
"name": "Objective name 2",
"health": 5,
"companyId": "60df26bfa259250cba9cf816",
"externalId": "12323",
"companyName": "Test Company"
"__v": 0,
"sourceId": "12323"
}'
https://api.planhat.com/objectives/:_id
To get a specific objective it's required to pass the _id in the request URL as a parameter.
Alternately it's possible to get an objective using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/objectives/extid-{{externalId}}
or
https://api.planhat.com/objectives/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/objectives/5ffcce42ad67267f66741147' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "5ffcce42ad67267f66741147",
"companyId": "56bccdf554d64d837d01be9d",
"companyName": "Tenet",
"name": "Gold objective",
"health": 5,
"__v": 0,
"custom": {
"Comments": "",
"Main Product": [
"Recipe Database"
],
"Days in Phase": 0,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Overall Outlet Health": 4,
"Kary FF": null
},
"externalId": "4467",
"usage": {
"6053b728fa96fa0262729a3d": 0,
"6053ba62ca3eaf023a54d268": 0
}
}'
https://api.planhat.com/objectives
When fetching multiple objectives there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/objectives?limit=2&offset=0&sort=-name&select=_id,name,health,companyId' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "60fb0869694ea374023924cb",
"companyId": "56bccdf554d64d837d01be4a",
"name": "ZPA Product",
"health": 5
},
{
"_id": "601c0a253e5ed41388982528",
"companyId": "6011889f52181c5640bf41ba",
"name": "Trello.io",
"health": 4
}
]'
https://api.planhat.com/objectives/:_id
To delete an objective it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/objectives/60faeda853b8f717ebe36146' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/objectives
To create an objective it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update an objective it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple objectives with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/objectives' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"name": "Objective name",
"companyId": "60df26bfa259250cba9cf816",
"health": 4,
"externalId": 1234,
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
}
},
{
"name": "Objective name 2",
"companyId": "60df26bfa259250cba9cf816",
"health": 5,
"externalId": 1235,
"sourceId": "sfc-1235",
"custom": {
"field": "custom field"
}
}
]'
200 OK
'{
"created": 2,
"createdErrors": [],
"insertsKeys": [
{
"_id": "60fde9ad57df5b411cf39be5",
"sourceId": "sfc-1234",
"externalId": "1234"
},
{
"_id": "60fde9ad57df5b411cf39be6",
"sourceId": "sfc-1235",
"externalId": "1235"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"60fde9ad57df5b411cf39be5",
"60fde9ad57df5b411cf39be6"
],
"permissionErrors": []
}'
https://api.planhat.com/projects
Projects can represent many different real world objects with a natural start and stop date. A service provider for schools may use Projects to represent classes or courses. If you're selling a software to run sales competitions, then each competition may be a project.
Using custom fields you can tailor projects to your needs, and just like Assets, usage data and time series data (metrics) can be associated with your Projetcs.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
name | string | Project name. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
externalId | string | The project id in your own system. | |
sourceId | string | The project id from an integration (Sales Force, Hubspot, etc). | |
currency | string | The currency code, for example "USD". | |
startDate | string | The project start date in ISO format. | |
endDate | string | The project end date in ISO format. | |
mrr | number | Monthly project value. | |
arr | number | Annual project value. | |
nrr | number | Non recurrent project value. | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/projects
To create an project it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/projects' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"companyId": "61006bc89a3e0b702ed8ea49",
"startDate": "2021-07-26T04:00:00.000Z",
"endDate": "2021-07-31T04:00:00.000Z",
"currency": "USD",
"mrr": 1000,
"name": "New project"
}'
200 OK
'{
"_id": "6101a50072c0e0884d5e8db1",
"companyId": "61006bc89a3e0b702ed8ea49",
"startDate": "2021-07-26T04:00:00.000Z",
"endDate": "2021-07-31T04:00:00.000Z",
"currency": "USD",
"mrr": 1000,
"name": "New project",
"companyName": "Tenet",
"__v": 0
}'
https://api.planhat.com/projects/:_id
To update an project it's required to pass the project _id in the request URL as a parameter.
Alternately it’s possible to update using the project externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/projects/extid-{{externalId}}
or
https://api.planhat.com/projects/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/projects/6101a50072c0e0884d5e8db1' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Big project"
}'
200 OK
'{
"_id": "6101a50072c0e0884d5e8db1",
"companyId": "61006bc89a3e0b702ed8ea49",
"startDate": "2021-07-26T04:00:00.000Z",
"endDate": "2021-07-31T04:00:00.000Z",
"currency": "USD",
"mrr": 1000,
"name": "Big project",
"companyName": "Tenet",
"__v": 0,
"custom": {
"Days until project end": 2
}
}'
https://api.planhat.com/projects/:_id
To get a specific project it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a project using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/projects/extid-{{externalId}}
or
https://api.planhat.com/projects/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/projects/609a88660b73992504816060' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "609a88660b73992504816060",
"companyId": "609975100b73992504810554",
"companyName": "Tenet",
"name": "SAP Integration",
"__v": 0,
"startDate": "2021-05-12T03:00:00.000Z",
"custom": {
"Notes": "",
"Product": [
"Product A"
],
"Days in Phase": 0,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
},
"mrr": 1000
}'
https://api.planhat.com/projects
When fetching multiple projects there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/projects?limit=2&offset=0&sort=-name&select=_id,name,companyId' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "60228bae4a93f65f056d2412",
"companyId": "6022884d40bd001fb4b6e554",
"name": "Älvdalen 2"
},
{
"_id": "60228915f4d2e51f9cc29856",
"companyId": "6022884d40bd001fb4b6e554",
"name": "URL123"
}
]'
https://api.planhat.com/projects/:_id
To delete an project it's required to pass the project _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/projects/6101a50072c0e0884d5e8db1' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/projects
To create a project it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a project it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple projects with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/projects' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"_id": "6101a50072c0e0884d5e8db1",
"mrr": 10000
},
{
"companyId": "61006bc89a3e0b702ed8ea49",
"startDate": "2021-07-25T04:00:00.000Z",
"endDate": "2021-07-30T04:00:00.000Z",
"currency": "USD",
"mrr": 5000,
"name": "Improvements"
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "6101a93e72c0e0884d5e8e52"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"6101a93e72c0e0884d5e8e52"
],
"permissionErrors": []
}'
https://api.planhat.com/sales
The Sale (NRR) model represents not recurring revenue, like an onboarding fee, or a one-off professional services project.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
_currency | string | The currency code, for example "USD". There is a "soft" mapping to the id’s in your list of currencies. Technically we accept any string but we recommend using standard currency codes as Ids. Since the mapping is soft you can add sales with a currency code not yet available in your list fo currencies. | |
product | string | Name of the sales product. Not required but highly recommended. Even if you only have one product we suggest adding it as "Advanced Onboarding". | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
externalId | string | The sale id in your own system. | |
sourceId | string | The sale id from an integration (Sales Force, Hubspot, etc). | |
salesDate | string | Date when sale was happened in ISO format. | |
value | number | The total sales value, must be positive. | |
custom | object | A flexible object with custom data. |
https://api.planhat.com/sales
To create a sale the only real value that is required is the companyId but it doesn't make much sense to have a sale just with a companyId, that is why we suggest specify a value and _currency.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/sales' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"product": "Advanced Onboarding",
"_currency": "USD",
"salesDate": "2021-07-28T00:00:00.000Z",
"value": 10000,
"companyId": "61006bc89a3e0b702ed8ea49"
}'
200 OK
'{
"value": 10000,
"_id": "61016c80675c1b871faf2d4f",
"product": "Advanced Onboarding",
"_currency": "USD",
"salesDate": "2021-07-28T00:00:00.000Z",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Tenet",
"__v": 0
}'
https://api.planhat.com/sales/:_id
To update a sale it's required to pass the sale _id in the request URL as a parameter.
Alternately it’s possible to update using the sale externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/sales/extid-{{externalId}}
or
https://api.planhat.com/sales/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/sales/61016c80675c1b871faf2d4f' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"mrr": 100000
}'
200 OK
'{
"_id": "61016c80675c1b871faf2d4f",
"value": 15000,
"product": "Advanced Onboarding",
"_currency": "USD",
"salesDate": "2021-07-28T00:00:00.000Z",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Tenet",
"__v": 0
}'
https://api.planhat.com/sales/:_id
To get a specific sale it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a sale using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/sales/extid-{{externalId}}
or
https://api.planhat.com/sales/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/sales/61016c80675c1b871faf2d4f' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"value": 10000,
"_id": "61016c80675c1b871faf2d4f",
"product": "Advanced Onboarding",
"_currency": "USD",
"salesDate": "2021-07-28T00:00:00.000Z",
"companyId": "61006bc89a3e0b702ed8ea49",
"companyName": "Tenet",
"__v": 0
}'
https://api.planhat.com/sales
When fetching multiple sales there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/sales?limit=2&offset=0&sort=-value&select=_id,product,value,companyId' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "59e04a67b640bc9e7c71f4a0",
"product": "UpStart Meeting",
"value": 300000,
"companyId": "56ccc2d39b760ff232295795"
},
{
"_id": "59e04a44b640bc9e7c71f497",
"product": "UpStart Meeting",
"value": 300000,
"companyId": "56ccc2d39b760ff232295795"
}
]'
https://api.planhat.com/sales/:_id
To delete a sale it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/sales/61016c80675c1b871faf2d4f' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/sales
To create a sale it's required define a companyId, _currency and value.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a sale it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple sales with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/sales' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"product": "Advanced Onboarding",
"_currency": "USD",
"salesDate": "2021-07-28T00:00:00.000Z",
"value": 5000,
"companyId": "61006bc89a3e0b702ed8ea49"
},
{
"_id": "61016c80675c1b871faf2d4f",
"value": 200000
}
]'
200 OK
'{
"created": 1,
"createdErrors": [],
"insertsKeys": [
{
"_id": "6101714572c0e0884d5e8160"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"6101714572c0e0884d5e8160"
],
"permissionErrors": []
}'
https://api.planhat.com/tasks
Tasks are the things that you plan to do in the future. It can be a simple "to-do" without any specific due date, a reminder of something to be done at a specific point in time, or even a meeting with a start and end time.
Most of the time these tasks will be automatically generated in Planhat based on rules you set up. It's also comon to have tasks as steps in a Playbook. But tasks can also be created ad-hoc just like you would in any task management app.
Tasks managed over the API should typically have the mainType property set to `task`, the other potential value is `event`, which indicates that it was synced to or from a calendar like Google Calendar. Though it's also possible to create tasks of type event in Planhat without syncing them back to any calendar.
Once a task is completed it's archived and genrally not visble in Planhat anymore. Sometimes when completing a tasks, say a training session, you want to log a note summarizing how it went, this is managed automatically by Planhat when working in the Planhat app.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
mainType | string | Required type should be always task. | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
startTime | string | ISO date when the task will starts. | |
dateDone | string | ISO date when the task was completed. | |
action | string | Title of the task, e.g. "Send Invoice" | |
description | string | Some description of the task. | |
repeat | string | If task repeatable then should send how often. The options are: daily, weekly, monthly, quarterly, yearly and custom. | |
repeatDays | integer | Number of days that the task will be repeated. Required if a custom repeat interval is set. | |
type | string | Type of task. | |
ownerId | objectId | ObjectId of the team member that owns the task. | |
ownerName | string | Owner name of the task. (Autogenerated). | |
doneBy | objectId | ObjectId of the team member who did he task. | |
sourceId | string | The task id from an integration (Sales Force, Hubspot, etc). | |
noSpecificTime | boolean | True if the task doesn't have any specific date to be executed. (Autogenerated). | |
shared | boolean | True if the task is shared. (Autogenerated). | |
overdueNotified | boolean | True if the task was notified due overdue. (Autogenerated). | |
activityTags | array | Array of string to tags. | |
isArchived | boolean | Flag the task as archived. | |
status | string | Each task can be assigned a status in Planhat. It’s a text string that should match the name of one of the task statuses in Planhat. If the name doesn’t match any of the statuses in Planhat it will still be saved. | |
checklist | array | Array of check list actions to be executed with the task. | |
snippet | string | Formatted content of the task. | |
endusers | array | Array of involved contacts. (Autogenerated). | |
users | array | Array of involved users. (Autogenerated). | |
custom | object | Custom object with your custom properties. | |
createdAt | string | An automatically created field that holds the Task creation ISO date. | |
updatedAt | string | Automatically created and updated field that holds the ISO date when the task was last modified. |
https://api.planhat.com/tasks
To create a task it is required a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
If the mainType is not specified it will be created with the default value: "task"
It is recommended to set the action field, think of it as the tasks title e.g. "Send Invoice"
curl --location -g --request POST 'https://api.planhat.com/tasks' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"ownerId": "58e231b14246fc73139f29e8",
"companyId": "61006bc89a3e0b702ed8ea49",
"mainType": "task",
"noSpecificTime": true,
"startTime": "2021-07-29T00:00:00.00Z",
"repeat": "daily",
"action": "New task",
"description": "Call the client.
"
}'
200 OK
'{
"mainType": "task",
"noSpecificTime": true,
"shared": false,
"overdueNotified": false,
"activityTags": [],
"isArchived": false,
"status": "In-progress",
"_id": "6102c9748084189dcbf0df60",
"ownerId": "58e231b14246fc73139f29e8",
"companyId": "61006bc89a3e0b702ed8ea49",
"startTime": "2021-07-29T00:00:00.000Z",
"repeat": "daily",
"action": "New task",
"description": "Call the client.
",
"snippet": "Call the client.",
"companyName": "Tenet",
"endusers": [],
"users": [],
"checklist": [],
"__v": 0,
"userEmail": "user@planhat.com",
"createdAt": "2022-07-05T09:51:52.818Z",
"updatedAt": "2022-07-05T09:51:52.818Z"
}'
https://api.planhat.com/tasks/:_id
To update an task it's required to pass the task _id in the request URL as a parameter.
curl --location -g --request PUT 'https://api.planhat.com/tasks/6102c9748084189dcbf0df60' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"action": "Daily contact",
"sourceId": "sfdc-1234"
}'
200 OK
'{
"mainType": "task",
"noSpecificTime": true,
"shared": false,
"overdueNotified": false,
"activityTags": [],
"isArchived": false,
"status": "In-progress",
"_id": "6102c9748084189dcbf0df60",
"ownerId": "58e231b14246fc73139f29e8",
"companyId": "61006bc89a3e0b702ed8ea49",
"startTime": "2021-07-29T00:00:00.000Z",
"repeat": "daily",
"action": "Daily contact",
"description": "Call the client.
",
"snippet": "Call the client.",
"companyName": "Tenet",
"endusers": [],
"users": [],
"checklist": [],
"__v": 0,
"ownerName": "Alex",
"sourceId": "sfdc-1234",
"createdAt": "2022-07-05T09:51:52.818Z",
"updatedAt": "2022-07-05T09:51:52.818Z"
}'
https://api.planhat.com/tasks/:_id
To get a specific task it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get a task using its sourceId adding a prefix and passing this keyable as identifier.
Example:
https://api.planhat.com/tasks/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/tasks/5db866ceab7aac67dc3637c8' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "5db866ceab7aac67dc3637c8",
"mainType": "task",
"noSpecificTime": true,
"shared": false,
"overdueNotified": false,
"activityTags": [],
"isArchived": false,
"status": "In-progress",
"action": "Sub activity",
"description": "",
"companyId": "56ccc2d39b760ff232295794",
"companyName": "Grand Hotels",
"createdAt": "2022-07-05T09:51:52.818Z",
"updatedAt": "2022-07-05T09:51:52.818Z",
"ownerId": "54ddc90a3570c76e2cbd08a5",
"ownerName": "Niklas",
"workflowId": "5db866ceab7aac67dc3637be",
"workflowName": "QBR",
"workflowTaskId": "5d27408853372f7cd1170407",
"checklist": [],
"parent": "5db866ceab7aac67dc3637c6",
"sortPosition": 5,
"snippet": "",
"endusers": [],
"users": [],
"children": [],
"comments": [],
"__v": 0,
"workflowTemplateId": "5a57d7754b5f1d13128a0533",
"repeat": null,
"custom": {
"HScore": 0
},
"workflowStepId": "5db866ceab7aac67dc3637c8"
}'
https://api.planhat.com/tasks
When fetching multiple tasks there are some options that can be used via query params:
companyId: Filter using company id. Multiple ids can be used separating them by commas.
limit: Limit the list length. Default as 500, max. 10000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
enduserIds: Filter using endusers id. Multiple ids can be used separating them by commas.
isArchived: Filter archived or not archived status. Default as false and this endpoint will returned objects where the mainType is `event` and `task`.
curl --location -g --request GET 'https://api.planhat.com/tasks?limit=2&offset=0' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "5da4bbec7b1616495b53a35b",
"mainType": "task",
"noSpecificTime": true,
"shared": false,
"overdueNotified": false,
"activityTags": [],
"isArchived": false,
"ownerId": "5524481f516d59216a6d2b80",
"companyId": "56bccdf554d64d837d01be96",
"companyName": "Daimler Group",
"createdAt": "2022-07-05T09:51:52.818Z",
"updatedAt": "2022-07-05T09:51:52.818Z",
"startTime": null,
"action": "Send them gift card",
"ownerName": "Sarah",
"endusers": [],
"users": [],
"children": [],
"comments": [],
"checklist": [],
"__v": 0,
"repeat": null,
"custom": {
"HScore": 0
}
},
{
"_id": "5db866ceab7aac67dc3637c8",
"mainType": "task",
"noSpecificTime": true,
"shared": false,
"overdueNotified": false,
"activityTags": [],
"isArchived": false,
"action": "Sub activity",
"description": "",
"companyId": "56ccc2d39b760ff232295794",
"companyName": "Grand Hotels",
"ownerId": "54ddc90a3570c76e2cbd08a5",
"ownerName": "Niklas",
"workflowId": "5db866ceab7aac67dc3637be",
"workflowName": "QBR",
"workflowTaskId": "5d27408853372f7cd1170407",
"checklist": [],
"parent": "5db866ceab7aac67dc3637c6",
"sortPosition": 5,
"snippet": "",
"endusers": [],
"users": [],
"children": [],
"comments": [],
"__v": 0,
"workflowTemplateId": "5a57d7754b5f1d13128a0533",
"repeat": null,
"custom": {
"HScore": 0
},
"workflowStepId": "5db866ceab7aac67dc3637c8"
},
{
"_id": "5f05cc03da205d2dfb2ad775",
"mainType": "event",
"noSpecificTime": true,
"shared": true,
"overdueNotified": false,
"activityTags": [],
"isArchived": false,
"action": "Test",
"description": "",
"companyId": "56bccdf554d64d837d01be55",
"companyName": "Sweco",
"ownerId": "564b063a508f068051ee82a5",
"ownerName": "Diego",
"workflowId": "5f05cc03da205d2dfb2ad773",
"workflowName": "Churn Prevention",
"workflowTaskId": "5ed7bba1492c366143976d13",
"workflowTemplateId": "57fdd14e8be8ceb43f8b1bc6",
"checklist": [
{
"title": "A"
},
{
"title": "B"
},
{
"title": "C"
}
],
"sortPosition": 1,
"snippet": "",
"endusers": [],
"users": [],
"children": [
{
"_id": "5f6889608baac92465787bf4"
}
],
"comments": [],
"__v": 0,
"custom": {
"HScore": 0
},
"workflowStepId": "5f05cc03da205d2dfb2ad775"
},
{
"_id": "5f317749604a74699f58f669",
"mainType": "event",
"noSpecificTime": true,
"shared": false,
"overdueNotified": false,
"activityTags": [],
"isArchived": false,
"status": "In-progress",
"companyId": "5942d6dfd4333a2f083011e8",
"companyName": "iBM",
"workflowId": "5f317728604a74699f58f65f",
"workflowName": "Test Playbook",
"workflowTemplateId": "5f317715d2b1cc0ebb619beb",
"action": "Test Event",
"description": "Book a thing
Was it fun?
",
"ownerId": "54ddc90a3570c76e2cbd08a5",
"ownerName": "Niklas",
"snippet": "Book a thing\n\nWas it fun?",
"endusers": [],
"users": [],
"children": [],
"comments": [],
"checklist": [],
"__v": 0,
"custom": {
"HScore": 0
},
"workflowStepId": "5f317749604a74699f58f669"
}
]'
https://api.planhat.com/tasks/:_id
To delete an task it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/tasks/6102c9748084189dcbf0df60' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{"n":1,"ok":1,"deletedCount":1}'
https://api.planhat.com/tasks
To create an issue it's required define a mainType and companyIds.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
If the mainType is not specified it will be created with the default value: "task"
It is recommended to set the action field, think of it as the tasks title e.g. "Send Invoice".
Since this is a bulk upsert operation it's possible create and/or update multiple tasks with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/tasks' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[{
"mainType": "task",
"startTime": "2022-07-05T14:02:16.181Z",
"ownerId": "61f91285d40d7d112020c7b6",
"ownerName": "Ernesto",
"action": "First Onboard Call",
"companyId": "5fd76c4daf9f4601dd313b05",
"checklist": [{
"title": "Prepare Material"
},
{
"title": "Present"
}
]
},
{
"mainType": "task",
"startTime": "2022-07-05T14:02:16.181Z",
"ownerId": "61f91285d40d7d112020c7b6",
"ownerName": "Ernesto",
"action": "Send Invoice",
"checklist": [],
"companyId": "60c10846108183032f05bd67"
},
{
"mainType": "task",
"startTime": "2022-07-05T14:02:16.181Z",
"ownerId": "61f91285d40d7d112020c7b6",
"ownerName": "Ernesto",
"companyId": "60c1075808f652259315e270",
"action": "Creating Tasks in bulk",
"description": "Description
",
"checklist": [{
"title": "Step 1"
},
{
"title": "Step 2"
}
]
}
]'
200 OK
'{
"created": 3,
"createdErrors": [],
"insertsKeys": [
{
"_id": "62c549dcfde99d59485c3314"
},
{
"_id": "62c549dcfde99d59485c3315"
},
{
"_id": "62c549dcfde99d59485c3316"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"62c549dcfde99d59485c3314",
"62c549dcfde99d59485c3315",
"62c549dcfde99d59485c3316"
],
"permissionErrors": []
}'
https://api.planhat.com/tickets
Tickets in Planhat are Conversations, so if you plan to send tickets to Planhat via API then you can also use that endpoint. The ticket endpoint contains a bit of convenience logic for save tickets specificially, like setting the proper type automatically.
Most of our customers sync tickets from an external system like Zendesk or Salesforce. In case your ticketing system isn't natively supported or you have your own system for it, please let us know and we'll be happy to discuss how to best work with this api.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
source | string | The name of the system this ticket originates from. Typically "Zendesk”, "Desk etc, but since you’re reading these docs you may have your tickets in some other tool. | |
companyId | objectId | Related company id (planhat identifier). | |
sourceId | string | Required. Id of the ticket in the source system. | |
string | Required. Email of the person who submitted the ticket. Items without email will be silently dropped. | ||
domains | array | Array of strings (required if companyExternalId not specified). | |
companyExternalId | string | The External Company Id. | |
title | string | If the ticket has a title or main subject. | |
description | string | Description of the ticket. | |
url | string | Url to where more information can be found about this ticket. | |
tags | array | Array of tags in string format. | |
type | string | the type of the ticket. Use as you like, but typically it could be: "bug", "feature request", "training" etc. | |
severity | string | String describing the severity, no restrictions on the scale apart from that. | |
product | string | Name of the product to which the ticket relates. | |
timeSpent | integer | Time spent on this ticket, measured in number of minutes. | |
status | string | Any status options you like. Typically "new", "pending", "open", "resolved", "closed" or something similar. | |
history | array | Array of object containing the status history of the ticket. |
To create a ticket it's required define a sourceId, email and domains.
To update a ticket it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId.
Since this is a bulk upsert operation it's possible create and/or update multiple tickets with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/tickets' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"sourceId": "119",
"source": "freshdesk",
"status": "open",
"history": [{"status": "open", "time": "2019-12-15T09:09:08.000Z"}],
"title": "Test Ticket",
"description": "Let have a chat?",
"url": "http://urltoyourticket.com/119",
"type": "ticket",
"email": "ojpsoi57pzn@gmail.com",
"name": "first-ojpsoi57pzn",
"companyId": "61006bc89a3e0b702ed8ea49",
"agentEmail": null,
"domains": ["planhat.com", "google.com"]
}
]'
200 OK
'{
"created": 1,
"updated": 0
}'
When fetching tickets there are some options that can be used via query params:
companyId: Filter using company id. Multiple ids can be used separating them by commas.
limit: Limit the list length. Default as 500, max. 10000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
status: Filter by status of tickets.
email: Filter by email.
search: Filter ticket searching for matching strings in the snippets.
curl --location -g --request GET 'https://api.planhat.com/tickets?s=open&cid=61006bc89a3e0b702ed8ea49&l=1' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "60d4e139e9c01e379effa355",
"externalId": "5003X00002CDLbHQAX",
"type": "ticket",
"source": "salesforce",
"subType": "ticket",
"subject": "[00001044] SFDC Case 1",
"snippet": "Test case from SFDC",
"email": "jbacon@gmail.com",
"status": "New",
"history": [
{
"status": "New",
"time": "2021-06-24T19:47:05.084Z"
}
],
"url": "https://eu29.salesforce.com/5003X00002CDLbHQAX",
"createDate": "2021-06-24T19:38:16.000Z",
"updateDate": "2021-06-24T19:38:16.000Z",
"date": "2021-06-24T19:38:16.000Z",
"days": 18802,
"timeBucket": [
"2021",
"2021-Q2",
"2021-6",
"2021-W26"
],
"companyId": "56bccdf554d64d837d01be80",
"companyName": "Exxon",
"endusers": [
{
"id": "5f7e1a07dcd4235b544f3ce4",
"name": "John Bacon"
}
],
"inDate": "2021-06-24T19:38:16.000Z",
"custom": {
"Closed Date": null,
"Created Date": "2021-06-24T19:38:16.000+0000",
"Days in Phase": 0,
"Logins": 0,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
},
"starred": false,
"pinned": false,
"activityTags": [],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"archived": false,
"users": [],
"sender": []
},
{
"_id": "5f579260f74efb6cfda04ba3",
"externalId": "5003X00001xQsPZQA0",
"type": "ticket",
"source": "salesforce",
"subType": "ticket",
"subject": "[00001036] Case - High Prio",
"snippet": "No enduser at first",
"email": "sean@edge.com",
"status": "Closed",
"history": [
{
"status": "Escalated",
"time": "2020-09-08T14:17:04.152Z"
},
{
"status": "Escalated",
"time": "2020-10-27T12:42:15.954Z"
},
{
"status": "Escalated",
"time": "2020-11-06T10:28:39.225Z"
},
{
"status": "Escalated",
"time": "2020-12-18T11:27:07.551Z"
},
{
"status": "Closed",
"time": "2020-12-18T11:29:53.022Z"
},
{
"status": "Closed",
"time": "2020-12-18T11:31:31.557Z"
},
{
"status": "Closed",
"time": "2020-12-18T11:32:41.930Z"
},
{
"status": "Closed",
"time": "2021-02-03T09:48:37.816Z"
},
{
"status": "Closed",
"time": "2021-04-09T13:03:03.578Z"
}
],
"url": "https://eu29.salesforce.com/5003X00001xQsPZQA0",
"createDate": "2020-09-08T14:14:01.000Z",
"updateDate": "2020-12-18T11:29:35.000Z",
"date": "2020-12-18T11:29:35.000Z",
"days": 18614,
"timeBucket": [
"2020",
"2020-Q4",
"2020-12",
"2020-W51"
],
"companyId": "56ccc2d39b760ff232295792",
"companyName": "Edge Communications",
"endusers": [
{
"id": "56ccc2d49b760ff23229579c",
"name": "Sean Morty"
}
],
"inDate": "2020-12-18T11:29:35.000Z",
"starred": false,
"pinned": false,
"activityTags": [],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"archived": false,
"users": [],
"sender": [],
"comments": [],
"custom": {
"t1": 0,
"Created date": "2020-09-08T14:14:01.000+0000",
"Closed Date": "2020-12-18T11:29:35.000+0000",
"Status": "Open",
"Created Date": "2020-09-08T14:14:01.000+0000",
"HScore": 0,
"Days in Phase": 0,
"Team Attendees": [
"58e231b14246fc73139f29e8"
],
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
}
}
]'
https://api.planhat.com/tickets/:_id
To delete an ticket it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/tickets/:_id' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"starred": false,
"pinned": false,
"autoTags": [],
"activityTags": [],
"emailTemplateIds": [],
"isOpen": false,
"tags": [],
"waitsToBeFiltered": true,
"timeBucket": [
"2021",
"2021-Q2",
"2021-6",
"2021-W26"
],
"archived": false,
"_id": "60d4e139e9c01e379effa355",
"externalId": "5003X00002CDLbHQAX",
"type": "ticket",
"source": "salesforce",
"subType": "ticket",
"subject": "[00001044] SFDC Case 1",
"snippet": "Test case from SFDC",
"email": "jbacon@gmail.com",
"status": "New",
"history": [
{
"status": "New",
"time": "2021-06-24T19:47:05.084Z"
}
],
"url": "https://eu29.salesforce.com/5003X00002CDLbHQAX",
"createDate": "2021-06-24T19:38:16.000Z",
"updateDate": "2021-06-24T19:38:16.000Z",
"date": "2021-06-24T19:38:16.000Z",
"days": 18802,
"companyId": "56bccdf554d64d837d01be80",
"companyName": "Exxon",
"endusers": [
{
"id": "5f7e1a07dcd4235b544f3ce4",
"name": "John Bacon"
}
],
"inDate": "2021-06-24T19:38:16.000Z",
"custom": {
"Closed Date": null,
"Created Date": "2021-06-24T19:38:16.000+0000",
"Days in Phase": 0,
"Logins": 0,
"Renewal in days": -1,
"Activity Count": 0,
"Week No": 29.285714285714285
},
"users": [],
"sender": []
}'
https://api.planhat.com/users
Users are all your team members that need access to Planhat. Users can be created in the app, using spreadsheet upload or over api.
If a user is flagged as inactive, they will not be able to login to Planhat and they will not get notifications, but they will be available for assigning accounts etc.
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
string | Email of the user. | ||
nickName | string | Nickname of user which will be shown in Planhat | |
firstName | string | First name of user. | |
lastName | string | Last name of user. | |
roles | array | Array of role ids assigned to the user. | |
externalId | string | The users' id in your system. | |
inactive | boolean | Sets the user in inactive state. A user set as inactive won't to able to login and won't receive notifications. Default as true. | |
image | object | Object containing the avatar information. (Autogenerated). | |
radarOneLine | boolean | Internal system field. (Autogenerated). | |
taskFilter | object | Object containing the task filter information. (Autogenerated). | |
companyFilter | string | Internal system field. (Autogenerated). | |
compressedView | boolean | Internal system field. (Autogenerated). | |
isHidden | boolean | Defines if the user is hidden within the syteam. | |
createDate | string | ISO date of when the user was created. (Autogenerated). | |
permissions | array | Array of user's permissions. (Autogenerated). | |
custom | object | A flexible object with custom data. |
https://api.planhat.com/users
To create an user it's required define in the payload a nickName, email, firstName and lastName.
curl --location -g --request POST 'https://api.planhat.com/users' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"email": "bob@test.com",
"firstName": "Bob",
"lastName": "Marley",
"nickName": "Bob",
"roles": [
"57e2b92ff795575a5b8c4659"
]
}'
200 OK
'{
"skippedGettingStartedSteps": {
"email": false,
"linkedin": false,
"avatar": false,
"all": false,
"team": false,
"customers": false
},
"sharedNotificationsPrefs": {
"enabled": [],
"disabled": [],
"disabledEvents": []
},
"image": {
"path": ""
},
"firstName": "Bob",
"lastName": "Marley",
"isHidden": false,
"removed": false,
"inactive": true,
"compressedView": false,
"companyFilter": "",
"taskFilter": "",
"workflowFilter": "",
"playLogDisabled": true,
"radarOneLine": false,
"expandedFolders": [],
"usageReportColumnsEnabled": [],
"companyUsersEnabledColumns": [],
"revReportPeriodType": "past x days",
"splitLayoutDisabled": false,
"dailyDigest": true,
"followerUpdate": true,
"inAppNotifications": true,
"lastVisitedCompanies": [],
"lastVisitedEndusers": [],
"roles": [
"57e2b92ff795575a5b8c4659"
],
"apiTokens": [],
"poc": [],
"isExposedAsSenderOption": false,
"defaultMeetingLength": 60,
"collapsedFolders": [],
"type": "user",
"_id": "61031e2ad414d49dcdb61b22",
"email": "bob@test.com",
"nickName": "Bob",
"createDate": "2021-07-29T21:31:22.042Z",
"__v": 0
}'
https://api.planhat.com/users/:_id
To update an user it's required to pass the user _id in the request URL as a parameter.
Alternately it’s possible to update using the user externalId adding a prefix.
Example:
https://api.planhat.com/users/extid-{{externalId}}
curl --location -g --request PUT 'https://api.planhat.com/users/61031e2ad414d49dcdb61b22' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"nickName": "Bob Marley"
}'
200 OK
'{
"_id": "61031e2ad414d49dcdb61b22",
"skippedGettingStartedSteps": {
"email": false,
"linkedin": false,
"avatar": false,
"all": false,
"team": false,
"customers": false
},
"sharedNotificationsPrefs": {
"enabled": [],
"disabled": [],
"disabledEvents": []
},
"image": {
"path": ""
},
"firstName": "Bob",
"lastName": "Marley",
"isHidden": false,
"removed": false,
"inactive": true,
"compressedView": false,
"companyFilter": "",
"taskFilter": "",
"workflowFilter": "",
"playLogDisabled": true,
"radarOneLine": false,
"expandedFolders": [],
"usageReportColumnsEnabled": [],
"companyUsersEnabledColumns": [],
"revReportPeriodType": "past x days",
"splitLayoutDisabled": false,
"dailyDigest": true,
"followerUpdate": true,
"inAppNotifications": true,
"lastVisitedCompanies": [],
"lastVisitedEndusers": [],
"roles": [
"57e2b92ff795575a5b8c4659"
],
"poc": [],
"isExposedAsSenderOption": false,
"defaultMeetingLength": 60,
"collapsedFolders": [],
"type": "user",
"email": "bob@test.com",
"nickName": "Bob Marley",
"createDate": "2021-07-29T21:31:22.042Z",
"__v": 0
}'
https://api.planhat.com/users/:_id
To get a specific user it's required to pass the _id in the request URL as a parameter.
Alternately it's possible get an user using its externalId adding a prefix.
Example:
https://api.planhat.com/users/extid-{{externalId}}
curl --location -g --request GET 'https://api.planhat.com/users/564b063a508f068051ee82a5' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "564b063a508f068051ee82a5",
"nickName": "Diego Checa",
"email": "diego@planhat.com",
"image": {
"path": ""
},
"radarOneLine": false,
"taskFilter": "",
"compressedView": false,
"isHidden": false,
"createDate": "2016-02-11T18:07:49.173Z",
"lastName": "",
"firstName": "Diego",
"__v": 13,
"dailyDigest": true,
"followerUpdate": true,
"permissions": {
"admin": true,
"changeOwner": true,
"onlyMyPortfolio": false,
"developer": true
},
"revReportPeriodType": "past x days",
"inAppNotifications": true,
"playlistSection": "all",
"lastDailyDigest": 18830,
"accountAccess": "all accounts",
"roles": [
{
"_id": "000000010000000000000000",
"name": "CSM",
"description": "Access to a few selected views and relevant accounts",
"__v": 393
},
{
"_id": "000000030000000000000000",
"name": "Developer",
"description": "Access to API keys, error pages etc",
"__v": 4
},
{
"_id": "000000000000000000000000",
"name": "Administrator",
"description": "Full access, including ability to edit users and settings",
"__v": 55
},
{
"_id": "000000020000000000000000",
"name": "Manager",
"description": "Access to the entire portfolio, and all functionality",
"__v": 56
}
],
"msApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedLabels": []
},
"playLogDisabled": true,
"poc": [
"Agreement"
],
"emailSignature": {
"content": "hello
",
"enabled": false
},
"inactive": false,
"removed": false,
"tzOffset": -5,
"intercomAdminId": "1123812",
"custom": {},
"defaultMeetingLength": 60,
"isExposedAsSenderOption": false,
"splitLayoutDisabled": false,
"recentOpenSharedView": "56bccdf554d64d837d01be63",
"invoicesSort": "-dueDate",
"type": "user",
"undefined": null,
"googleApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedLabels": []
},
"googleCalendarApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedCalendars": [],
"calendarToSave": {}
},
"msCalendarApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedCalendars": [],
"calendarToSave": {}
}
}'
https://api.planhat.com/users
When fetching multiple projects there are some options that can be used via query params:
limit: Limit the list length. Default as 10000, max. 10000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/users' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "564b063a508f068051ee82a5",
"nickName": "Diego Checa",
"email": "diego@planhat.com",
"image": {
"path": ""
},
"radarOneLine": false,
"taskFilter": "",
"compressedView": false,
"isHidden": false,
"createDate": "2016-02-11T18:07:49.173Z",
"lastName": "",
"firstName": "Diego",
"__v": 13,
"dailyDigest": true,
"followerUpdate": true,
"permissions": {
"admin": true,
"changeOwner": true,
"onlyMyPortfolio": false,
"developer": true
},
"revReportPeriodType": "past x days",
"inAppNotifications": true,
"playlistSection": "all",
"lastDailyDigest": 18830,
"accountAccess": "all accounts",
"roles": [
{
"_id": "000000010000000000000000",
"name": "CSM",
"description": "Access to a few selected views and relevant accounts",
"__v": 393
},
{
"_id": "000000030000000000000000",
"name": "Developer",
"description": "Access to API keys, error pages etc",
"__v": 4
},
{
"_id": "000000000000000000000000",
"name": "Administrator",
"description": "Full access, including ability to edit users and settings",
"__v": 55
},
{
"_id": "000000020000000000000000",
"name": "Manager",
"description": "Access to the entire portfolio, and all functionality",
"__v": 56
}
],
"msApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedLabels": []
},
"playLogDisabled": true,
"poc": [
"Agreement"
],
"emailSignature": {
"content": "hello
",
"enabled": false
},
"inactive": false,
"removed": false,
"tzOffset": -5,
"intercomAdminId": "1123812",
"custom": {},
"defaultMeetingLength": 60,
"isExposedAsSenderOption": false,
"splitLayoutDisabled": false,
"recentOpenSharedView": "56bccdf554d64d837d01be63",
"invoicesSort": "-dueDate",
"type": "user",
"undefined": null,
"googleApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedLabels": []
},
"googleCalendarApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedCalendars": [],
"calendarToSave": {}
},
"msCalendarApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedCalendars": [],
"calendarToSave": {}
}
},
{
"_id": "5524481f516d59216a6d2b80",
"nickName": "Sarah",
"email": "sarah@planhat.com",
"image": {
"spacesKey": "arrivato/team/5524481f516d59216a6d2b80_1527055421955.png",
"path": ""
},
"radarOneLine": false,
"taskFilter": "{\"owner\":\"5524481f516d59216a6d2b80\"}",
"compressedView": false,
"isHidden": false,
"createDate": "2016-02-11T18:07:49.171Z",
"lastName": "Jones",
"firstName": "Sarah",
"__v": 2,
"permissions": {
"admin": true,
"changeOwner": true,
"onlyMyPortfolio": false,
"developer": false
},
"segment": null,
"playlistStyle": "calendar",
"followerUpdate": false,
"revReportPeriodType": "static",
"revReportStartDay": 90,
"revReportStartDate": "2020-08-01T00:00:00.000Z",
"playlistSection": "all",
"dailyDigest": true,
"bubbleChartXParam": "time-to-renewal",
"inAppNotifications": true,
"revReportEndDate": "2020-09-01T00:00:00.000Z",
"convReportEndDate": "2019-01-24T23:59:59.999Z",
"convReportStartDate": "2018-10-26T23:00:00.000Z",
"lastDailyDigest": 18831,
"accountAccess": "all accounts",
"googleApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedLabels": []
},
"msApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedLabels": []
},
"playLogDisabled": true,
"roles": [
{
"_id": "000000020000000000000000",
"name": "Manager",
"description": "Access to the entire portfolio, and all functionality",
"__v": 56
},
{
"_id": "000000000000000000000000",
"name": "Administrator",
"description": "Full access, including ability to edit users and settings",
"__v": 55
},
{
"_id": "000000010000000000000000",
"name": "CSM",
"description": "Access to a few selected views and relevant accounts",
"__v": 393
}
],
"custom": {
"Role": "CSM"
},
"disableIncludeChildrenPref": false,
"inactive": false,
"isExposedAsSenderOption": true,
"poc": [],
"removed": false,
"tzOffset": 1,
"splitLayoutDisabled": false,
"intercomAdminId": "1019963",
"recentOpenSharedView": "56bccdf554d64d837d01be9d",
"opportunitiesSort": "landingDate",
"opportunitiesColumnPref": {
"companyName": true,
"title": false,
"Status": false,
"comment": false,
"ownerId": true,
"probability": false,
"mrr": false,
"dealDate": false,
"custom-% to Close": false,
"custom-Owner": true,
"custom-Technical Rep": true
},
"issuesColumnPref": {
"title": true,
"createdAt": true,
"status": true,
"companies": true,
"custom-Priority": true,
"endusers": false,
"description": false,
"source": false,
"sourceId": false,
"projectId": false,
"issueType": false,
"priority": false,
"sourceUrl": false,
"updatedAt": false,
"sourceKey": false
},
"defaultMeetingLength": 60,
"type": "user",
"undefined": null,
"googleCalendarApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedCalendars": [],
"calendarToSave": {}
},
"msCalendarApi": {
"accessEnabled": false,
"syncEnabled": false,
"syncInitial": false,
"syncedCalendars": [],
"calendarToSave": {}
}
}
]'
https://api.planhat.com/users/:_id
To delete an user it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/users/61031e2ad414d49dcdb61b22' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{}'
https://api.planhat.com/users
To create an enduser it's required define a nickName, email, firstName and lastName.
To update an enduser it is required to specify in the payload one of the following keyables, listed in order of priority: _id, externalId, email.
Since this is a bulk upsert operation it's possible create and/or update multiple users with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/users' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"email": "rob@test.com",
"firstName": "Robbert",
"lastName": "Rob",
"nickName": "Tyler",
"roles": [
"57e2b92ff795575a5b8c4659"
]
},
{
"email": "liz@test.com",
"firstName": "Liz",
"lastName": "Elizabeth",
"nickName": "Gates",
"roles": [
"5d35c292344cb854c0a5af28"
]
}
]'
200 OK
'{
"created": 2,
"createdErrors": [],
"insertsKeys": [
{
"_id": "61033193e41b0aa81c926c8b",
"email": "rob@test.com"
},
{
"_id": "61033193e41b0aa81c926c8c",
"email": "liz@test.com"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"61033193e41b0aa81c926c8b",
"61033193e41b0aa81c926c8c"
],
"permissionErrors": []
}'
https://api.planhat.com/workspaces
If you work with sub-instances at your customers, e.g., connecting with different departments or with different versions of your product (think like a Workspace in Slack), then this is the object to track that engagement!
Property | Required | Type | Description |
---|---|---|---|
_id | objectId | Planhat identifier. | |
name | string | Workspace name. | |
ownerId | objectId | Related owner id (planhat identifier). | |
companyId | objectId | Related company id (planhat identifier). | |
companyName | string | Company name. (Autogenerated). | |
externalId | string | The workspace id in your own system. | |
sourceId | string | The workspace id from an integration (Sales Force, Hubspot, etc). | |
custom | object | Custom object with your custom properties. |
https://api.planhat.com/workspaces
To create a workspace it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
curl --location -g --request POST 'https://api.planhat.com/workspaces' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Workspace name",
"companyId": "60df26bfa259250cba9cf816",
"ownerId": "60df26bfa259250cba8cf310",
"externalId": 1234,
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
}
}'
200 OK
'{
"_id": "60faeda853b8f717ebe36146",
"name": "Workspace name",
"companyId": "60df26bfa259250cba9cf816",
"ownerId": "60df26bfa259250cba8cf310",
"externalId": "1234",
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
},
"companyName": "Test Company"
}'
https://api.planhat.com/workspaces/:_id
To update a workspace it's required to pass the _id in the request URL as a parameter.
Alternately it’s possible to update using the workspace externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/workspaces/extid-{{externalId}}
or
https://api.planhat.com/workspaces/srcid-{{sourceId}}
curl --location -g --request PUT 'https://api.planhat.com/workspaces/60faeda853b8f717ebe36146' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '{
"name": "Workspace name 2"
}'
200 OK
'{
"_id": "60ff061d681a6b4da9248694",
"name": "Workspace name 2",
"companyId": "60df26bfa259250cba9cf816",
"ownerId": "60df26bfa259250cba8cf310",
"externalId": "12323",
"companyName": "Test Company"
"__v": 0,
"sourceId": "12323"
}'
https://api.planhat.com/workspaces/:_id
To get a specific workspace it's required to pass the _id in the request URL as a parameter.
Alternately it's possible to get a workspace using its externalId and/or sourceId adding a prefix and passing one of these keyables as identifiers.
Example:
https://api.planhat.com/workspaces/extid-{{externalId}}
or
https://api.planhat.com/workspaces/srcid-{{sourceId}}
curl --location -g --request GET 'https://api.planhat.com/workspaces/5ffcce42ad67267f66741147' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"_id": "5ffcce42ad67267f66741147",
"companyId": "56bccdf554d64d837d01be9d",
"ownerId": "60df26bfa259250cba8cf310",
"companyName": "Tenet",
"name": "Gold workspace",
"__v": 0,
"custom": {
"Comments": "",
"Main Product": [
"Recipe Database"
],
"Days in Phase": 0,
"NRR30": 0,
"t123": "undefined",
"Logins": 0,
"Overall Outlet Health": 4,
"Kary FF": null
},
"externalId": "4467",
"usage": {
"6053b728fa96fa0262729a3d": 0,
"6053ba62ca3eaf023a54d268": 0
}
}'
https://api.planhat.com/workspaces
When fetching multiple workspaces there are some options that can be used via query params:
companyId: Filter using company id.
limit: Limit the list length. Default as 100, max. 2000.
offset: Start the list on a specific integer index.
sort: Sort based on a specific property. Prefix the property "-" to change the sort order.
select: Select specific properties. Multiple properties can be specified separating them by commas.
curl --location -g --request GET 'https://api.planhat.com/workspaces?limit=2&offset=0&sort=-name&select=_id,name,companyId,ownerId' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'[
{
"_id": "60fb0869694ea374023924cb",
"companyId": "56bccdf554d64d837d01be4a",
"name": "ZPA Product",
"ownerId": "60df26bfa259250cba8cf310"
},
{
"_id": "601c0a253e5ed41388982528",
"companyId": "6011889f52181c5640bf41ba",
"name": "Trello.io",
"ownerId": "60df26bfa259250cba8cf310"
}
]'
https://api.planhat.com/workspaces/:_id
To delete a workspace it's required to pass the _id in the request URL as a parameter.
curl --location -g --request DELETE 'https://api.planhat.com/workspaces/60faeda853b8f717ebe36146' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}'
200 OK
'{
"n": 1,
"ok": 1,
"deletedCount": 1
}'
https://api.planhat.com/workspaces
To create a workspace it's required define a name and a valid companyId.
You can instead reference the company externalId or sourceId using the following command structure: "companyId": "extid-[company externalId]" or "companyId": "srcid-[company sourceId]".
To update a workspace it is required to specify in the payload one of the following keyables, listed in order of priority: _id, sourceId, externalId.
Since this is a bulk upsert operation it's possible create and/or update multiple workspaces with the same payload.
For more details please refer to the bulk upsert section.
Note: There is an upper limit of 5,000 items per request.
curl --location -g --request PUT 'https://api.planhat.com/workspaces' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {{apiToken}}' \
--data-raw '[
{
"name": "Workspace name",
"companyId": "60df26bfa259250cba9cf816",
"ownerId": "60df26bfa259250cba8cf310",
"externalId": 1234,
"sourceId": "sfc-1234",
"custom": {
"field": "custom field"
}
},
{
"name": "Workspace name 2",
"companyId": "60df26bfa259250cba9cf816",
"ownerId": "60df26bfa259250cba8cf310",
"externalId": 1235,
"sourceId": "sfc-1235",
"custom": {
"field": "custom field"
}
}
]'
200 OK
'{
"created": 2,
"createdErrors": [],
"insertsKeys": [
{
"_id": "60fde9ad57df5b411cf39be5",
"sourceId": "sfc-1234",
"externalId": "1234"
},
{
"_id": "60fde9ad57df5b411cf39be6",
"sourceId": "sfc-1235",
"externalId": "1235"
}
],
"updated": 0,
"updatedErrors": [],
"updatesKeys": [],
"nonupdates": 0,
"modified": [],
"upsertedIds": [
"60fde9ad57df5b411cf39be5",
"60fde9ad57df5b411cf39be6"
],
"permissionErrors": []
}'