The Simplicate REST API
This is the documentation for the Simplicate v2 API. Read the contents of this page carefully. We make changes to the APIs from time to time. Endpoints are documented with the HTTP method for the request and a partial resource identifier.
Example:
GET /api/v2/crm/organization
Prepend your Simplicate URL to the resource identifier to get the full endpoint URL:
https://{yourdomain}.simplicate.nl/api/v2/crm/organization
The examples in the docs are cURL statements. You can run the statements on a command line to try out different API requests. To learn more, see Installing and using cURL. In Windows, you'll need to modify some of the examples in the docs to make them work. When documenting a resource, we use curly braces, {}, for identifiers.
Example: https://{yourdomain}.simplicate.nl/api/v2/crm/organization
For a full list of available endpoints, please see the API Reference.
Security and Authentication
This is an SSL-only API, regardless of how your account is configured.
You can authorize against the API using a tokenized approached based on API Key and Secret. You can create multiple API tokens for various purposes. API tokens are managed in the General settings under the API section in your Simplicate environment. The page lets you view, add, or delete tokens. More than one token can be active at the same time. Every API token inherits its rights from the user it was created for. Deleting a token deactivates it permanently.
Add the following authentication variables with every request header:
Authentication-Key: {API Key}
Authentication-Secret: {API Secret}
curl -H "Authentication-Key: {API Key}" -H "Authentication-Secret: {API secret}" https://{subdomain}.simplicate.nl/api/v2/crm/organization
Rate Limiting
This API is rate limited. We only allow a certain number of requests per minute. We reserve the right to adjust the rate limit for given endpoints to provide a high quality of service for all clients. As an API consumer, you should expect to be able to make at least 60 requests per minute. If the rate limit is exceeded, Simplicate responds with a HTTP 429 Too Many Requests
Request Format
The Simplicate API is a JSON-only API. You must supply a Content-Type: application/json header in all requests. You may get a text/plain response in case of an error like a bad request. You should treat this as an error you need to resolve.
Response Format
Simplicate responds to successful requests with HTTP status codes in the 200 range. When you create a resource, depending on the resource Simplicate renders the resulting created resource ID in the response body.
Simplicate responds to unsuccessful requests with HTTP status codes in the 400 range. The content type of the response may be text/plain for API-level error messages, such as when trying to call the API without SSL. The content type is application/json for business-level error messages because the response includes a JSON object with information about the error:
{
"data": null,
"errors": ["No country code given in the visiting_address property"],
"debug": null
}
If you experience responses with status codes in the 500 range, Simplicate may be experiencing internal issues or undergoing scheduled maintenance, during which we send a 503 Service Unavailable status code. When building an API client, we recommend treating any 500 status codes as a warning or temporary state. However, if the status persists and we don't have a publicly announced maintenance or service disruption, contact us at support@simplicate.nl.
Questions and Support
If you encounter any issues when using our APIs, please contact us at support@simplicate.nl.
Please note that we cannot help you develop software or scripts to connect with our API - support is limited to the actual API-calls themselves. We can direct you to the appropriate API call and explain how it works, but we do not provide substantive support in setting up the calls or developing integrations.
Use Cases
Obtaining the PDF of an invoice
After obtaining an invoice ID from /invoices/invoice, use /invoices/document to find the relevant document(s):
/invoices/document?q[linked_to.invoice_id]=invoice:abcdef
You'll find a list of documents pertaining to the invoice. Locate the document you wish to download. In the result set you'll find a download_url property. Please note that this URL requires a valid web session on the Simplicate application. To programmatically download the documents, please continue.
From the result of /invoices/document, use the id (as document:abcdef), to proceed to:
/documents/download/document:abcdef
This is the location of the actual document. If the document is a PDF, the API will respond with a Content-Type: application/pdf header. In all other cases, the API will respond with Content-Type: application/octet-stream header.
Please note: the /invoices/document and /documents/download API's are protected by all the relevant rights in the Simplicate application. When trying to download documents, please make sure you're using the API keys of a user who has access to these documents.
Uploading, Linking, and Using Files
Uploading files
When uploading documents to Simplicate, you'll follow this flow:
- Let the API know your intentions; what's the file name, of what file size
- Upload the file (repeatedly if need be), in chunks of max
500 kB. - The API will let you know you've uploaded all you needed, and that the file is complete
- You'll be able to create a document, and link to this file, or use it as an attachment in timeline messages
Start by letting the API know you're about to submit a file. Send the following body to /upload/chunked.
POST /api/v2/upload/chunked
{
"file_name": "simplicate-logo.png",
"file_size": 858
}
Note that file size is in bytes. The result will be like:
200 OK
{
"data": {
"chunked_upload_id": "chunkedupload:a00a5662be4cf8b54da2058e5c846d06"
}
}
We're going to use this ID to start uploading the actual contents of the file. Please note that the file contents must be base64 encoded, and each chunk must not exceed 500 kB (base64 encoded).
PUT /api/v2/upload/chunked/chunkedupload:a00a5662be4cf8b54da2058e5c846d06
{
"chunk": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAACxKAAAsSgF3enRNAAADDElEQVRIiY1VO2hUQRTd7LoRjYpg/EOipEgRxUJRDNgoVhZKUAu/BH8E0lgoNjbpFNGAhZ95hQTnqYU2In6QFBoEg2gjFiYiJiKopHCeEgWT9dyZM7uzEXb2weG+N2/u78y9d3K54EmTLKcTIzKvlZXL0sSchRwCJoAS8BN4g/+XIdeldp8RvQbRr/nQeIPGRsjDUPymnVGPXzA8jfVSquz3FHAO79aJ6NZ2oEyeG89oGMC3GBnB2inILcBaYCPQ7bIydGzuAo2iG3MgkXQFEQ8A81KX0QzYQPrECbM8XwdFWRM2jdL4nSqDyiyCsTVAi1CJYMTxI+79iLWOqAPHu1X4Dqxwhm20vaDsM//9wFo/5CAjH4PxNjlsoTiWwX3yeo0UCA4GlJlUmfDQx+C4HRDjBR07Ayh8peIxW7IKpafMMJ3eAJbivYd7xvF/JYPISwXVQ9EfKu/lQc6B9NRspVPZtxNyNeRy4AIw2wcUczBOCnpdA9noBl0G5jEoKGq/7uRr7frhnj0rFc3ApDZalaUuIutge8D5Q8s1uxffR+Foik13qR6KdrFLJ/He4SqIB63K3fsAe2aVx4oyJ4MANtR0wFExzM3PoVwMnBwIM8F6YzWNmTTcrVgGknonKPhLQ09tJysXMXCo7ERl1xmQlHc3K22ytgPwS0N7GBGGnVnINf4zJzgeZPCtohN0eDYtFNaRga1pcbYjdXUupdgPg/PZ2XPFODPZTJ0WwGYdy4CjAfw6xWYYe8/0pUw7gavOuJH7YTGzWu+pqyeDAp20wtiorkzLkh/PdpQn2Wntp6qtJNsrE5EMcJM5J0LNiHZKL4Dd+H4C+QHyFXBcVyatZPuWGVys6YBKbam9ZKzCEA6yKRgRS7CnmFbfCVdSP2UT0xpxIHdrto0VZB0A7SzFmZdNM+SA5x4B9NTRyeUrs8tXBfAbHN+EPCJDDtgnVQU6vwSN18fxEbmTwzJNsk3Ay8CIHxUlNxBldJhP+N4fUBjJoNL6Ba8EyGhOgGdYe0ent+2gS7IFzNgH9Z/NfzoINxdnkeUkAAAAAElFTkSuQmCC"
}
As this file is way smaller than 500 kB, the API will set the state to 'done', and no new chunks will be accepted:
200 OK
{
"data": {
"pointer": 1,
"state": "done",
"upload_queue_id": "uploadqueue:7de64ec93190dd457a9bfc4dc6429b75",
"file_size_current": 858,
"file_size_expected": 858,
"download_url": "/download?name=simplicate-logo.png"
},
"errors": null,
"debug": null
}
If you're uploading a larger file, the API will respond like below, and you'll need to send the remaining chunks, until the file is completely uploaded:
200 OK
{
"data": {
"pointer": 1,
"state": "in_progress",
"file_size_current": 384000,
"file_size_expected": 3781286
},
"errors": null,
"debug": null
}
Converting to document
With the upload_queue_id in hand, we can convert this file to a document, with a title, a document type id, and link it to an existing entity (Person, Organization, Sales, Project, Invoice)
POST /api/v2/documents/document
{
"upload_queue_id": "uploadqueue:7de64ec93190dd457a9bfc4dc6429b75",
"title": "simplicate-logo.png",
"document_type_id": "documenttype:b423eae1f54f879041c55b3092b4a1f8",
"linked_to": {
"person_id": "person:b1c692b0993bb602eb694ed52cdf49ac"
}
}
---
200 OK
{
"data": {
"id": "document:91b5a2aee0d60fae298fdc63dd8ada0b"
}
}
This file can now be found in its linked entity, on the tab 'Documents'.
As a timeline message attachment
Additionally, if you wish to link this document to a timeline message, then please see POST /timeline/attachmentTimeline/post_timeline_attachment), and send the following request:
POST /api/v2/timeline/attachment
{
"message_id": "message:914edc4509a28e23ccd1f796716510b1",
"document_id": "document:91b5a2aee0d60fae298fdc63dd8ada0b"
}
That's it for uploading files, and using them as documents!
PHP example for uploading chunks
A PHP example for uploading a file, in chunks:
function uploadFileToApi(string $fileName, string $filePath): string
{
$uploadId = $this->callSimplicate('POST', '/upload/chunked', [
'file_name' => $fileName,
'file_size' => filesize($filePath),
]);
$chunkSize = 500 * 1000; // 500 kB, times a thousand, for bytes, to err on the side of caution
$base64String = base64_encode(file_get_contents($filePath));
$offset = 0;
while (true) {
$chunk = substr($base64String, $offset, $chunkSize);
$offset += $chunkSize;
$apiResponse = $this->callSimplicate('PUT', '/upload/chunked/' . $uploadId, [
'chunk' => $chunk,
]);
if (!isset($apiResponse['data']) || !isset($apiResponse['data']['state'])) {
throw new Exception('Expected a successful API response, with data and data.state');
}
if ($apiResponse['data']['state'] === 'done') {
return $apiResponse['data']['upload_queue_id'];
}
}
}
$uploadQueueId = uploadFileToApi('simplicate-logo.png', '/path/to/simplicate-logo-24x24px.png');
Tracking Creates and Updates
You can combine the filtering and sorting parameters to keep track of what was created or updated since the last API call:
/crm/organization?q[updated_at][ge]=2025-12-29+00:00:00&sort=-updated_at
Our Zapier integration uses this same method.
See also: Known Limitations > Tracking Deletions