PlanningPME API - Developer documentation
Interconnect your planning data with the rest of your information system.
PlanningPME allows read and write access to your database through a dedicated API.
The PlanningPME API follows the current development standard (REST implementation and JSON formatted data transport) for a simple programming of your synchronizations and integrations.
This document will inform you about:
How to determine your PlanningPME API address ?Where to find your interactive documentation ?
How the security is implemented in PlanningPME API ?
What are the common data considerations in PlanningPME API ?
How to make your first requests to PlanningPME API ?
PlanningPME API is based on RESTful principles, and the default data transfer format is JSON.
This documentation is mainly for developers. We recommend the reader to familiarize with JSON REST API programming before going further.
Dedicated URL
Each PlanningPME client has its own dedicated API address.
Say your brand name is "MyCompany", you should probably use the brand key "mycompany" (ignoring case) in order to build your API address.
This key will be noted as "your_brand" in the rest of this documentation.
The base API address of a brand will always be :
https://api.planningpme.com/your_brand/
or
https://try.planningpme.com/your_brand/
Interactive documentation
Each brand API also presents an interactive documentation, very useful to discover your PlanningPME API methods and models and build API calls.
This documentation is available at the following address :
https://api.planningpme.com/your_brand/doc/index
or
https://try.planningpme.com/your_brand/doc/index
Those two addresses cannot be called without presenting an application key.
Note: In the event that account authentication is enabled on your API, access to interactive documentation is one click away within the PlanningPME account application.
Security
1/ Application key presentation
You need an application key (appkey) in order to access your API, thus identifying the caller application.
This appkey is available in your PlanningPME account (if account authentication is enabled on your API), or on demand to the support.
In addition to securing API access, the appkey let you grant access to a partner or a tier-application, by bringing them their own key to identify their calls to the API.
The appkey should always be passed in the headers of an API call, by using dedicated "X-APPKEY" header.
GET /your_brand/api/config HTTP/1.1 Host: api.planningpme.com X-APPKEY: e991573da5ffd4sab9b1e26bc6b64aac
To access your interactive documentation, use the appkey as an address parameter, as in the example below.
https://api.planningpme.com/your_brand/doc/index?appkey=e991573da5ffd4sab9b1e26bc6b64aac
2/ User token and impersonation
Most API requests must also have an authorization token, in order to determine the profile of the user accessing the data, and respect the user and group permissions defined in the application.
This token is previously obtained when authenticating a user at /token, and remains valid for 8 hours.
The data posted to this address differs depending on the authentication mode chosen for your application.
a) Classic authentication
If enabled, conventional authentication is achieved by posting the username and password.
POST /your_brand/token HTTP/1.1 Host: api.planningpme.com X-APPKEY: e991573da5ffd4sab9b1e26bc6b64aac Content-Type: application/x-www-form-urlencoded grant_type=password&username=your_username&password=your_password
b) Account authentication
If enabled, account authentication is done by posting a service account token, previously obtained in the PlanningPME account application.
For each user listed here, you can copy the service account token to your clipboard.
Now get an authorization token from your API, by posting the copied account token (assertion).
POST /your_brand/token HTTP/1.1 Host: api.planningpme.com X-APPKEY: e991573da5ffd4sab9b1e26bc6b64aac Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=account_token
c) Use of the authorization token
In the case of successful authentication, the response body will contain a JSON element as follows.
{ "access_token": "KTuZYDLG2qjUMqMVXDuiP9giFbqDXstESvpUWzBFLpkfdlMiB3PD5s2K7En-3o39u56hpr_DlyjEc_...3Is0gcH", "token_type": "bearer", "expires_in": 86399, "username": "your_username" }
The “access_token” property contains the API authorization token.
Also, as indicated by the "token_type" property, this token is of type "bearer". Requests requiring authorization must therefore present the "Authorization" header with the value "Bearer", as in the example below.
POST /your_brand/api/customer HTTP/1.1 Host: api.planningpme.com X-APPKEY: e991573da5ffd4sab9b1e26bc6b64aac Authorization: Bearer KTuZYDLG2qjUMqMVXDuiP9giFbqDXstESvpUWzBFLpkfdlMiB3PD5s2K7En-3o39u56hpr_DlyjEc_...3Is0gcH
API usage
1/ Common data considerations
a) Models
PlanningPME data models can be easily discovered by using the interactive documentation of your API.
b) Date format
Date format used by the API and expected in each JSON request is ISO 8601 format. Ex:
2018-01-25T18:05:00Z
c) Sorting lists
GET methods often use a "sortInfo" parameter to set the sorting order of the full/paginated list returned.
This info is composed with the name of a property directly followed by a + or - sign.
For instance use "label+" in order to sort by ascending "label" property.
It is also possible to combine multiple orders by appending them.
For instance use "notValid-label+" to sort by descending "notValid" property then by ascending "label" property.
Be aware that property labels are case sensitive.
d) Constant enumerations
Complete list of enums in use with your API version is obtained by calling the "/api/config" method. This list is not entitled to change except future addition.
GET /your_brand/api/config HTTP/1.1 Host: api.planningpme.com X-APPKEY: e991573da5ffd4sab9b1e26bc6b64aac
Below is the list of enums in version 4.7.0.26
{ ... "enums": { "Access": { "All": "All", "Read": "Read", "Write": "Write" }, "BillingType": { "Package": "Package", "Unit": "Unit" }, "ColorDepending": { "Label": "Label", "Category": "Category", "Customer": "Customer", "Time": "Time", "Project": "Project" }, "ConfigType": { "ExportTemplates": "ExportTemplates", "TimeRestrictedView": "TimeRestrictedView", "Filterings": "Filterings", "Language": "Language", "DateTimeFormat": "DateTimeFormat", "GCSync": "GCSync", "EffectTemplates": "EffectTemplates", "SyncResource": "SyncResource", "PrintTemplates": "PrintTemplates" }, "ConstraintAction": { "NoTaskBeforeNbHours": "NoTaskBeforeNbHours", "NoTaskBeforeNbDays": "NoTaskBeforeNbDays", "NoTaskSamePeriod": "NoTaskSamePeriod", "NbMaxHours": "NbMaxHours", "NbMax": "NbMax", "DurationMaxHours": "DurationMaxHours", "DurationMaxDays": "DurationMaxDays" }, "ConstraintFor": { "All": "All", "Resources": "Resources", "Departments": "Departments" }, "ConstraintIf": { "Nothing": "Nothing", "Nb": "Nb", "NbHours": "NbHours", "Begin": "Begin", "End": "End" }, "ConstraintOp": { "Nothing": "Nothing", "Equal": "Equal", "Inf": "Inf", "InfEqual": "InfEqual", "Sup": "Sup", "SupEqual": "SupEqual", "Before": "Before", "After": "After" }, "ConstraintType": { "Task": "Task", "Unavailability": "Unavailability" }, "ConstraintWhat": { "LabelAll": "LabelAll", "LabelExact": "LabelExact", "LabelBegin": "LabelBegin" }, "ConstraintWhen": { "Nothing": "Nothing", "Day": "Day", "Week": "Week", "Month": "Month", "Year": "Year" }, "CountHolidays": { "Five": "Five", "Six": "Six" }, "CurrencyCode": { "GBP": "GBP", "EUR": "EUR", "USD": "USD", "DEM": "DEM", "FRF": "FRF", "CHF": "CHF", "ARS": "ARS", "BRL": "BRL", "CLP": "CLP", "CRC": "CRC", "RUB": "RUB", "GTQ": "GTQ", "PAB": "PAB", "PYG": "PYG", "PEN": "PEN", "UYU": "UYU", "SVC": "SVC", "HNL": "HNL", "NOK": "NOK", "CNY": "CNY", "JPY": "JPY", "CAD": "CAD" }, "CustomerType": { "Individual": "Individual", "Company": "Company" }, "DataFieldType": { "Date": "Date", "Time": "Time", "Text": "Text", "Numeric": "Numeric", "Double": "Double", "Combo": "Combo", "Link": "Link", "Check": "Check", "Memo": "Memo", "Separator": "Separator", "File": "File", "Position": "Position", "SignatureMobile": "SignatureMobile", "Hyperlink": "Hyperlink", "ProjectStartDate": "ProjectStartDate", "ProjectEndDate": "ProjectEndDate", "ProjectDuration": "ProjectDuration", "ProjectDeadline": "ProjectDeadline", "ProjectDeadlineOver": "ProjectDeadlineOver", "Signature": "Signature", "ProjectEstimateDuration": "ProjectEstimateDuration", "SubProjectEstimateDuration": "SubProjectEstimateDuration" }, "DescriptionFieldType": { "Index1": "Index1", "Index2": "Index2", "EmailBody": "EmailBody", "Label": "Label", "Mobile": "Mobile", "CalendarBody": "CalendarBody", "EmailSubject": "EmailSubject", "Tooltip": "Tooltip", "LabelAssignment": "LabelAssignment", "CalendarSubject": "CalendarSubject", "Print": "Print", "LabelUnavailability": "LabelUnavailability", "PrintUnavailability": "PrintUnavailability" }, "DescriptionFieldStyle": { "Normal": "Normal", "Bold": "Bold", "Italic": "Italic", "Underline": "Underline" }, "DescriptionFieldColor": { "Custom": "Custom", "Default": "Default", "Destination": "Destination" }, "Destination": { "Task0": "Task0", "Task2": "Task2", "Task3": "Task3", "Task4": "Task4", "Task5": "Task5", "Equipment0": "Equipment0", "Customer1": "Customer1", "MaterialResource1": "MaterialResource1", "MaterialResource2": "MaterialResource2", "MaterialResource3": "MaterialResource3", "Project0": "Project0", "HumanResource1": "HumanResource1", "HumanResource2": "HumanResource2", "Task1": "Task1", "HumanResource3": "HumanResource3", "Customer0": "Customer0", "HumanResource0": "HumanResource0", "Customer2": "Customer2", "MaterialResource0": "MaterialResource0", "Customer3": "Customer3", "Project1": "Project1", "Project2": "Project2", "SubProject0": "SubProject0", "Project3": "Project3" }, "DestinationType": { "Task": "Task", "Customer": "Customer", "Equipment": "Equipment", "Resource": "Resource", "Project": "Project", "SubProject": "SubProject" }, "DoMode": { "None": "None", "End": "End", "Duration": "Duration" }, "EffActionType": { "Email": "Email", "Sms": "Sms", "MicrosoftOutlook": "MicrosoftOutlook", "GoogleCalendar": "GoogleCalendar" }, "EffIfType": { "Category": "Category", "Status": "Status" }, "EffIfOp": { "IsIn": "IsIn", "BecomesIn": "BecomesIn" }, "EffSourceType": { "Customer": "Customer", "Resource": "Resource", "Project": "Project", "Status": "Status", "ResourceIn": "ResourceIn", "ProjectIn": "ProjectIn", "TaskIn": "TaskIn", "Assignment": "Assignment", "Unavailability": "Unavailability", "Task": "Task" }, "EffStepType": { "Start": "Start", "End": "End", "Insert": "Insert", "Delete": "Delete", "Unperiodize": "Unperiodize", "Update": "Update" }, "EffSubjectType": { "Assignment": "Assignment", "Unavailability": "Unavailability", "Task": "Task" }, "EffTargetType": { "Customer": "Customer", "Resource": "Resource", "User": "User", "Account": "Account" }, "HistoryOp": { "Insert": "Insert", "Delete": "Delete", "Email": "Email", "Invitation": "Invitation", "Unperiodize": "Unperiodize", "Session": "Session", "Update": "Update" }, "HistoryType": { "Assignment": "Assignment", "Customer": "Customer", "SessionDesktop": "SessionDesktop", "Unavailability": "Unavailability", "SessionMobile": "SessionMobile", "Project": "Project", "Resource": "Resource", "Task": "Task", "SessionWebAccess": "SessionWebAccess" }, "InRootType": { "Customer": "Customer", "Project": "Project", "Resource": "Resource" }, "JoinStatus": { "Invited": "Invited", "Connected": "Connected" }, "JsonWritingType": { "None": "None", "Normal": "Normal", "KeyLabel": "KeyLabel", "String": "String", "Data": "Data" }, "LicenseStatus": { "Other": "Other", "Evaluation": "Evaluation", "Ok": "Ok", "NoExpirationDate": "NoExpirationDate", "WrongDatabase": "WrongDatabase", "WrongMachine": "WrongMachine", "ResourceCount": "ResourceCount", "LicenseCount": "LicenseCount", "Expired": "Expired", "Empty": "Empty", "Corrupted": "Corrupted" }, "LinkRefType": { "Assignment": "Assignment", "Customer": "Customer", "Unavailability": "Unavailability", "Project": "Project", "Resource": "Resource", "Task": "Task" }, "NotificationType": { "None": "None", "TaskInsert": "TaskInsert", "TaskUpdate": "TaskUpdate", "UnavailabilityInsert": "UnavailabilityInsert", "UnavailabilityUpdate": "UnavailabilityUpdate" }, "OneOrMoreCustomers": { "OneCustomer": "OneCustomer", "MoreCustomer": "MoreCustomer" }, "OneOrMoreResources": { "OneResource": "OneResource", "MoreResource": "MoreResource" }, "RecurrenceDaily": { "AllThe": "AllThe", "AllWorkingDays": "AllWorkingDays" }, "RecurrenceMonthly": { "Date": "Date", "Day": "Day" }, "RecurrenceMonthlyDayWhich": { "First": "First", "Second": "Second", "Third": "Third", "Fourth": "Fourth", "Last": "Last" }, "RecurrenceRange": { "NoEndDate": "NoEndDate", "EndThe": "EndThe" }, "RecurrenceType": { "Daily": "Daily", "Weekly": "Weekly", "Monthly": "Monthly", "Yearly": "Yearly" }, "ResourceType": { "Human": "Human", "Material": "Material", "ToPlan": "ToPlan", "Extern": "Extern" }, "StatusType": { "Task": "Task", "Unavailability": "Unavailability" }, "SyncType": { "_Google": "_Google", "Microsoft": "Microsoft", "Google": "Google" }, "TaskType": { "Default": "Default", "Duration": "Duration", "Time": "Time" }, "Title": { "Miss": "Miss", "Mr": "Mr", "Ms": "Ms" }, "TimeLapseUnit": { "Day": "Day", "Week": "Week", "Month": "Month", "Year": "Year" }, "TypeHatch": { "BDIAGONAL": "BDIAGONAL", "CROSS": "CROSS", "DIAGCROSS": "DIAGCROSS", "FDIAGONAL": "FDIAGONAL", "HORIZONTAL": "HORIZONTAL", "VERTICAL": "VERTICAL" }, "WorkCapacity": { "Hours": "Hours", "Slots": "Slots" } }, ...
e) Response language
The language used in response texts such as error messages can be specified with the "Accept-Language" header.
Accept-Language: en
The languages available in PlanningPME API and PlanningPME WebAccess are: German (de), English (en), Danish (da), Spanish (es), Finnish (fi), French (fr), Italian (it), Japanese (ja), Dutch(nl), Norwegian (no), Polish (pl), Portuguese (pt), Russian (ru),Swedish (sv).
2/ Examples of API calls
In the examples below, the application key used is noted "your_key", and the authorization token "your_token". Please replace them with your own values.
/api/task
→ Get a full or paginated list of tasks with GET "/api/task" method.
GET /your_brand/api/task?pageIndex=1&pageSize=20&sortInfo=label+ HTTP/1.1 Host: api.planningpme.com X-APPKEY: your_key Authorization: Bearer your_token
Returns an array of tasks containing second page of 20 tasks ordered by descending label.
{ "totalItems": 97, "items": [ { "key": 756, "label": "Cours d'anglais pour enfant", "type": 1467, "style": { "backgroundColor": "#65A18D", "color": "#000000" } }, ... { "key": 131, "label": "Coaching", "type": 1467, "style": { "backgroundColor": "#214DE9", "color": "#000000" } } ] }
→ Get a detailed task with GET "/api/task/{id}" method.
GET /your_brand/api/task/756 HTTP/1.1 Host: api.planningpme.com X-APPKEY: votre_clé Authorization: Bearer your_token
Returns a detailed task object representation of the task with id 756.
{ "key": 756, "label": "Cours d'anglais pour enfant", "type": 1467, "style": { "backgroundColor": "#65A18D", "color": "#000000" }, "skills": [ [ { "key": 12, "name": "Enfant", "label": "Pédagogie > Enfant", "level": 1, "domain": { "key": 4, "label": "Pédagogie" } }, { "key": 83, "name": "Anglais", "label": "Langue > Anglais", "level": 1, "domain": { "key": 4, "label": "Langue" } } ] ] }