{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"afc5d66a-7284-46de-9d3c-92bc9f5ffb96","name":"AdminPulse API","description":"This documentation describes the AdminPulse API endpoints. In case you have any feedback or miss certain functionality, let us know via [support@adminpulse.eu](https://)\n\n# API endpoint\n\n- The base API endpoint for all requests (excluding the authentication calls) is: [https://api.adminpulse.be](https://api.adminpulse.be)\n    \n\n# Status codes\n\n- `200` OK: the request was processed successfully\n    \n- `400` Bad request: the endpoint was called using invalid data\n    \n- `401` Unauthorized: invalid or missing access token\n    \n- `404` Resource not found: make sure the correct URL was used\n    \n- `429` Too many requests: the rate limit is currently set at 480 calls/min. Except for the documents/add call. That one allows for 50 calls/min.\n    \n- `500` Internal Server Error: an unexpected error occurred. Contact support if this problem keeps occurring.\n    \n\n# Authentication\n\nThe AdminPulse API offers 2 authentication methods:\n\n- OAuth with callback URL (recommended)\n    \n- Using an [API key](https://adminpulse.zendesk.com/hc/articles/8331100368924)\n    \n\nWhichever authentication method is used, the token or key always has to be added to the `Authorization` header with a `Bearer` prefix to access all API endpoints. Example: `Authentication: Bearer xyz`\n\nIf you are a 3rd party integrator and want to make an API integration for multiple accounting offices, send a request to [support@adminpulse.eu](https://) to request a `client_id` and `client_secret.` Tell us about your usecase and which redirect URL(s) you want to use and we will gladly assist you.\n\n## OAuth with callback URL\n\nKeep in mind that you will have to register a `redirect URL` as well. This URL will be called after the user has logged in.\n\nExample: [<i>https://yourcompany.com/adminpulse/callback</i>](https://)\n\n###### 1\\. Setup the authorization URL\n\nThe authorization URL is: [<code>https://login.adminpulse.be/connect/authorize</code>](https://)\n\nThe following query string parameters should be added. Make sure to sure URL encoding.\n\n- `client_id` the client ID that you received from the AdminPulse team\n    \n- `response_type=code`\n    \n- `scope=api.connect` api.connect is currently the only scope available. Add the `offline_access` scope in to be able to request refresh tokens. See other scopes below.\n    \n- `redirect_uri` this is the callback URL that you registered with the AdminPulse team.\n    \n- `state` optionally you can pass state which will be included when the callback URL is called.\n    \n\nThis is an example of a full authorization URL: [<code>https://login.adminpulse.be/connect/authorize?client_id=</code><code><i><b>&amp;response_type=code&amp;scope=api.connect offline_access&amp;redirect_uri=https://</b></i></code><code>/callback</code>](https://)\n\n_Note: keep in mind that scopes need to be space delimited (using the encoding)_\n\n###### 2\\. Obtaining an access token\n\nAfter the authorization URL has been called and the user logged in successfully, the callback URL is called using a `GET` request with a query string parameter `code`. This code will be used to obtain an access token.\n\nThe token endpoint is: [<code>https://login.adminpulse.be/connect/token</code>](https://)\n\nRequest headers:\n\n`Content-Type`: application/x-www-form-urlencoded\n\nMake a `POST` call with the following **x-www-form-urlencoded** data in the request body:\n\n- `code`: the code received via query string parameters\n    \n- `redirect_uri`: [https://yourcompany.com/adminpulse/callback](https://)\n    \n- `grant_type:` authorization_code\n    \n- `client_id`: the client ID that you received from the AdminPulse team\n    \n- `client_secret`: the client secret that you received from the AdminPulse team\n    \n\nYou receive the following parameters in the JSON body response:\n\n- `access_token`: the actual access token that will be used in the Authorization header for further requests to all API endpoints. Valid for 1 hour.\n    \n- `token_type`: the token type will always be Bearer\n    \n- `expires_in`: when the access token will expire (in seconds)\n    \n- `refresh_token`: the refresh token. Store this so a new access token can be requested when the access token expired.  \n    The refresh token itself is valid for 90 days. since the last time you used it. When using the refresh token to request a new access token, you will also receive a new refresh token which will again be valid for 90 days.  \n    If the refresh token is not used within the 90 day period, the user will have to re-authenticate.\n    \n\n###### 3\\. Refreshing an access token\n\nThe endpoint is: [<code>https://login.adminpulse.be/connect/token</code>](https://)\n\nMake a `POST` call with the following x-www-form-urlencoded data:\n\n- `refresh_token`: the refresh token that you stored from a previous request\n    \n- `grant_type=refresh_token`\n    \n- `client_id`: the client ID that you received from the AdminPulse team\n    \n- `client_secret`: the client secret that you received from the AdminPulse team\n    \n\nYou receive the following parameters in the JSON body response:\n\n- `access_token`: a new access token. Valid for 1 hour.\n    \n- `token_type`: the token type will always be Bearer\n    \n- `expires_in`: when the access token will expire (in seconds)\n    \n- `refresh_token`: the refresh token. Store this so a new access token can be requested when the access token expired.  \n    The refresh token itself is valid for 90 days. since the last time you used it. When using the refresh token to request a new access token, you will also receive a new refresh token which will again be valid for 90 days.  \n    If the refresh token is not used within the 90 day period, the user will have to re-authenticate.\n    \n\n## Using an API key\n\nIn this case, a token will have to be generated by the customer (the accountant) by going to the \"My profile\" page in AdminPulse or using this link: [https://app.adminpulse.be/#/profile/accesstokens](https://).\n\nThis token does not need to be refreshed. You can use it in the Authorization header: `Authorization: Bearer`\n\n# Scopes\n\nThese scopes are available when obtaining an access token. Any required scope is mentioned per call below.\n\n- documents.read\n    \n- documents.write\n    \n- interactions.write\n    \n- invoices.read\n    \n- invoices.write\n    \n- relations.read\n    \n- relations.write\n    \n- registrations.read\n    \n- registrations.write\n    \n- tasks.read\n    \n- tasks.write\n    \n- users.read\n    \n- users.write\n    \n- pricelistitems.read\n    \n- notifications.read\n    \n- notifications.write\n    \n\nWhen using an API key for authentication, scopes are defined during the creation of the API key.\n\n# Rate limit\n\nYour calls are rate limited by a combination of your unique client_id and the tenant you're making calls for (with a fallback value of the caller's IP Address).\n\nThe amount of calls remaining can be checked by looking at these response headers of each request:\n\n- **x-remaining-calls-per-minute**: The amount of calls you can still make.\n    \n- **x-total-calls-per-minute**: The total amount of calls you can make per minute.\n    \n\nPlease note: the minute referred to above is a sliding window. The rate limit is currently set at **480 calls/min**. Except for the documents/add call. That one allows for **50 calls/min.**\n\n# Webhooks\n\n#### Introduction\n\nWebhooks provide a way for AdminPulse to automatically send real-time notifications to another application when specific events occur. Instead of constantly checking for updates, webhooks ensure that relevant information is sent to a designated URL when an event takes place.\n\nWhile there might be a slight delay (max 2 minutes) due to event batching, webhooks enable efficient and timely communication between different systems.\n\n#### Entities\n\nThe support entities are:\n\n- _registration_\n    \n- _relation_\n    \n- _task_\n    \n- _taskschedule_\n    \n- _invoice_\n    \n- _document_\n    \n- _documentContent_\n    \n- email\n    \n- _user_\n    \n\n#### Events\n\nYou can subscribe to the following events:\n\n- _created_\n    \n- _updated_\n    \n- _deleted_\n    \n\n#### How the webhook is sent\n\nAdminPulse will send a **POST** request to your registered URL. The body of this request will contain a json object with the following structure:\n\n- AppId - string\n    \n- Items - array of item:\n    \n    - EntityId - string - the id of the entity for which we send a webhook. Eg: relationId\n        \n    - EntityType - string - the entity type\n        \n    - Event - string - _created_/_updated_/_deleted_\n        \n\n**Please note** that the webhook response does not include the actual values related to the event. To obtain the latest version of the affected entity and its associated information, you should make a subsequent call to our API using the provided details.\n\n#### When the webhook is sent\n\nDepending on the entity type, an event will be sent for a specific entity with the corresponding event type.\n\n**Registration**\n\n- created when the registration was created\n    \n- updated when the registration was modified (including when it was invoiced on a **finalized** invoice, not an invoice in its draft state)\n    \n- deleted when the registration was deleted\n    \n\n**Relation**\n\n- _created_ when the related was created\n    \n- _updated_ when\n    \n    - any of the relation fields were changed\n        \n    - a bank account was changed\n        \n    - an address was changed\n        \n    - the budget of the relation was changed\n        \n    - the invoice schedule of the relation was changed\n        \n\n**Task**\n\n- _created_ when the task was created\n    \n- _updated_ when\n    \n    - task deadline was changed\n        \n    - task tags were changed\n        \n    - task relation was changed\n        \n    - task assigned user was changed\n        \n\n**Taskschedule**\n\n- _created_ when the task schedule (on a relation) was created\n    \n- _updated_ when the task schedule was changed\n    \n\n**Invoice**\n\n- _created_ when a **finalized** invoice was created. A draft invoice that was processed and received an invoice number.\n    \n- _updated_ when\n    \n    - the invoice was edited\n        \n    - the invoice was paid or the payment was removed\n        \n- _deleted_ when an invoice was unnumbered (moved back to draft invoices)\n    \n\n**Document**\n\n- _created_ when the document was created\n    \n- _updated_ when document metadata was changed (not its content)\n    \n- _deleted_ when the document was deleted\n    \n\n**DocumentContent**\n\n- _updated_ when the content of a document was modified or replaced\n    \n\nEmail\n\n- _created_ when the email was created\n    \n\n**User**\n\n- created when a new user was added to the AdminPulse account\n    \n- updated when the user's metadata was changed\n    \n- deleted when the user is removed from the AdminPulse account\n    \n\n#### Retries\n\nWhen the webhook does not receive a success status code (200/202/204), a retry will be attempted later on. Each webhook message will be retried 4 times. The delay is gradually increased between retries.\n\n- 5 minutes\n    \n- 1 hour\n    \n- 5 hours\n    \n- 10 hours\n    \n\n#### Disabling of webhooks\n\nIf the webhook does not respond with a success status code for a long time, it will be disabled to prevent endless load on both AdminPulse and the target system.\n\nThe webhook will be disabled when:\n\n- the webhook was created more than one week ago\n    \n- in the last week we did not receive a success response\n    \n- in the last week at least 100 attempts were made to call the webhook\n    \n\nWhen the webhook is disabled, an e-mail is sent to the administrators of the AdminPulse account to notify them.\n\n#### Message authenticity\n\nWhen registering a webhook, you will receive an app id and app key (see [https://developer.adminpulse.be/#9a7ad413-fb05-4e76-a0c6-444f9159d037](https://developer.adminpulse.be/#9a7ad413-fb05-4e76-a0c6-444f9159d037)). It is recommended you store these values, so you can use them later when a webhook is received by your system. This way, you are 100% sure that the webhook was sent by AdminPulse and not by a malicious party.\n\nWebhook events can be validated using the HMAC signature present on the `X-HMAC-Signature` header.  \nAn example of the value of this header is  \n`Hmac HMACSHA256:SHA256:software.client:TnMMKIuazB0v1u+95awoNRDQbTUmHC/uqZDezJPtIdg=:67ddb60519c04e4ea6186a2480e0ee06:1755853921`\n\nThe value is colon-separated constructed string consisting of:\n\n- the authentication scheme (Hmac)\n    \n- the HMAC hashing method (HMACSHA256)\n    \n- The request body hashing method (SHA256)\n    \n- the app id (software.client)\n    \n- the base64 version of a hashed string that consists of the app id, the HTTP request method in uppercase (POST), the url encoded request URL, the request timestamp in unix seconds, a nonce and a base64 version of the hashed request body\n    \n- a nonce\n    \n- request timestamp in unix seconds\n    \n\nTo validate the signature, you will need to:\n\n- hash the received json payload using SHA256\n    \n- convert this string to base64\n    \n- construct a string made up of these variables. Make sure the casing of the urlEncodedWebhookUrl uses capital casing: a slash should be / and not /.  \n    \"{appId}{httpMethod}{urlEncodedWebhookUrl}{receivedTimestamp}{receivedNonce}{base64HashedPayload}\"\n    \n- hash this string using HMACSHA256, where the hashing key is your app key that you received when the webhook was created\n    \n- compare the constructed string with the string received in the header above (`TnMMKIuazB0v1u+95awoNRDQbTUmHC/uqZDezJPtIdg`) in our example\n    \n- if both strings match, the webhook was called by AdminPulse\n    \n\n# Changelog\n\n#### 2025 - december\n\n- add webhook support for email, taskschedule\n    \n- add option to pass unitPrice when creating a registration\n    \n- add option to get assignments without invoice schedule on /relations/invoiceschedules\n    \n\n#### 2025 - october\n\n- add lastSyncTime query parameter to \"list tasks\" endpoint\n    \n- add lastSyncTime query parameter to \"list users\" endpoint\n    \n- include assignment info in registration response\n    \n- include invoice attachments in invoice response\n    \n- include initials in relation response (NL)\n    \n- add option to pass companyId and teams when adding a relation\n    \n- add option to pass start date of invoice schedule when adding an invoice schedule\n    \n- add option to override existing invoice schedule / set a new amount\n    \n- add some remarks to the documentation of validating message authenticity when using our webhooks. The casing on the url encoded endpoint url should be capital case.\n    \n\n#### 2025 - june\n\n- add endpoints to list, create, update and delete task schedules\n    \n- include task periodicities in /tasks/templates endpoint\n    \n- add endpoint to get all invoice schedules for all relations: /relations/invoiceschedules\n    \n\n#### 2025 - may\n\n- add webhook support for document, documentContent, registration and user\n    \n- add endpoints to list, create and update planned registrations\n    \n- add endpoint to list pricetables\n    \n- add endpoint to link a todo to an interaction\n    \n- add endpoint to add an attachment to an interaction\n    \n- add sendInvoiceStrategy, sendInvoiceSoftware, receiveInvoiceSoftware, otherSoftware and accountingSoftware to relation response\n    \n- add endpoints to list teams, add, update and remove user from a team","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":true,"owner":"5560360","collectionId":"afc5d66a-7284-46de-9d3c-92bc9f5ffb96","publishedId":"TzJsgdv7","public":true,"publicUrl":"https://developer.adminpulse.be","privateUrl":"https://go.postman.co/documentation/5560360-afc5d66a-7284-46de-9d3c-92bc9f5ffb96","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"5FA3C0"},"documentationLayout":"classic-double-column","customisation":null,"version":"8.10.0","publishDate":"2023-04-05T12:10:31.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{},"logos":{}},"statusCode":200},"environments":[{"name":"live","id":"1b5884a3-6ef3-4c53-83de-c8234998a7a3","owner":"5560360","values":[{"key":"apiEndpointUrl","value":"https://api.adminpulse.be","enabled":true},{"key":"identityTokenUrl","value":"https://login.adminpulse.be/connect/token","enabled":true},{"key":"authorizeTokenUrl","value":"https://login.adminpulse.be/connect/authorize","enabled":true,"type":"default"}],"published":true}],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/0428d44ea88c7ebc3e5c3b25d055d4c75a092df425a1211e076d0c1acf050efd","favicon":"https://res.cloudinary.com/postman/image/upload/v1686060430/team/m83ycot7q9mozbwwfut2.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"},{"label":"live","value":"5560360-1b5884a3-6ef3-4c53-83de-c8234998a7a3"}],"canonicalUrl":"https://developer.adminpulse.be/view/metadata/TzJsgdv7"}